MySQL优化 JOIN语法和JOIN算法

本文问题

  1. 什么是外联接,什么是内联接?
  2. MySQL中的JOIN语法与标准SQL语法有什么不同?
  3. MySQL Join算法有几种?
  4. NLJ算法的过程是怎样的?
  5. BNL算法的过程是怎样的?

join语法

外联接和内联接

  • 内联接:INNER JOIN是内联接
    内连接中,结果中只包括同时符合WHERE条件及ON条件的行
  • 外联接:LEFT JOINRIGHT JOIN都是外联接
    外联接中,T2中的行可以不符合ON条件,如果T2中的没有符合ON条件的行,使用NULL代替T2中的列值
# 联接条件使用`ON`表示
# 外联接
SELECT * FROM T1 LEFT JOIN T2 ON T1.C1=T2.C2
# 内联接
SELECT * FROM T1 INNER JOIN T2 ON T1.C1=T2.C2

MySQL对JOIN语法的扩展

MySQL中,可以将多个表放在括号中,表示多表内联接:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
# 等同与
SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

在MySQL中,CROSS JOIN在语法上等同与INNER JOIN,他们可以互相替代。在标准SQL中,他们是不同的,INNER JOIN可以使用ON子句,CROSS JOIN不行。

Join算法

MySQL在表中执行join联结使用nested-loop算法或该算法的变体

  • Nested-Loop Join(NLJ)
  • Block Nested-Loop Join(BNL)

Nested-Loop Join算法

简单的nested-loop join(NLJ)算法是一次将第一个表中的一行读取到循环中,将每行放入到一个处理下一个join的表的嵌套循环中。如果仍有其他表加入,重复这个过程。
假设有一个在t1,t2,t3三个中的join操作,执行以下类型的join

Table   Join Type
t1      range
t2      ref
t3      ALL

如果使用简单NLJ算法,join的过程如下:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    }
  }
}

由于NLJ算法从外循环到内循环处理行数据,通常会多次读取内循环中的表。

Block Nested-Loop Join算法

Block Nested-Loop(BNL)算法缓冲在外循环中读取的行,来减少读取内循环表的次数。例如,如果将10行数据读取到缓冲区中,然后将缓冲区传入到内循环,内循环中读取的行可以一次与缓冲区中的10行数据进行对比,这可以减少读取内循环中的表的次数。

MySQL join缓冲区具有以下特征:

  • join类型为ALLindex,或者为range时,可以使用join缓冲区。缓冲区也可以应用于外联接。
  • 即使类型为ALLindexjoin buffer不会分配给非常量表。
  • 只将join相关的列存储到join buffer,不会将整行都存储到join buffer
  • join_buffer_size决定了处理查询时每个join buffer的大小
  • 为每个可以被缓冲的join分配缓冲区,所以一个查询在处理过程中可能会使用多个缓冲区
  • 缓冲区在执行join前分配,在查询完成后释放

对于之前NLJ算法的示例,如果使用join buffer,过程如下:

# 就是每当join buffer满后,对内层的表进行一次扫描并返回结果,然后清空join buffer。
# 由于数据量不一定会总是填满join buffer。最后还要再检查一次join buffer,如果不为空的话,再对内层的表进行一次扫描

for each row in t1 matching range {
  for each row in t2 matching reference key {
    store used columns from t1, t2 in join buffer
    if buffer is full {
      for each row in t3 {
        for each t1, t2 combination in join buffer {
          if row satisfies join conditions, send to client
        }
      }  # for each row in t3 循环结束
      empty join buffer
    } #if buffer is full 循环结束
  } # for each row in t2 循环结束
} # for each row in t1 循环结束

if buffer is not empty { 
  for each row in t3 {
    for each t1, t2 combination in join buffer {
      if row satisfies join conditions, send to client
    }
  }
}

S是存储在缓冲区中的t1,t2组合大小,C是组合数量。扫描t3表的次数是:
(S * C)/join_buffer_size + 1
增加join_buffer_size可以降低t3的扫描次数,直到join_buffer_size足够大,可以容纳所有的行组合,在这种情况下,增加缓冲区不能继续提升性能。

问题答案

  1. 什么是外联接,什么是内联接?
  • 内联接:INNER JOIN是内联接
    内连接中,结果中只包括同时符合WHERE条件及ON条件的行
  • 外联接:LEFT JOINRIGHT JOIN都是外联接
    外联接中,T2中的行可以不符合ON条件,如果T2中的没有符合ON条件的行,使用NULL代替T2中的列值
  1. MySQL中的JOIN语法与标准SQL语法有什么不同?
  • MySQL可以将多个表放在括号中,表示多表内联接,如(T2,T3,T4)=(T2 CROSS JOIN T3 CROSS JOIN T3)。标准SQL不支持这么写
  • MySQL中的CROSS JOIN等同与INNER JOIN。标准SQL中,INNER JOIN可以包含ON条件,CROSS JOIN只能使用WHERE条件
  1. MySQL Join算法有几种?区别是什么?
    2种
    Nested-Loop Join算法,简称NLJ
    Block Nested-Loop Join算法,简称BNL
    BNL算法使用缓冲区缓存外层表的数据,以减少内层表的循环查询过程。
  2. NLJ算法的过程是怎样的?
    读取第一个表中符合条件的行,将其放入到下层循环中,进入下一层循环处理(检查该行数据是否匹配其他条件),如果有其他要join的表,重复该过程。
  3. BNL算法的过程是怎样的?
    将第一个表中符合条件的行中于join相关的列放入到join buffer
    join bufffer满后,将join buffer放入下层循环中,进入下一层循环处理(检查join buffer中的行数据是否匹配其他条件),如果有其他要join的表,重复该过程。在循环中,返回匹配的行。
    处理结束后清空join buffer,对第一个表继续进行循环
    循环结束后,检查join buffer是否为空,如果join buffer不为空,检查join buffer中的行数据是否匹配其他条件。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348