介绍
MySQL使用嵌套循环算法或其变体在表之间执行连接。
- Nested-Loop Join Algorithm
- Block Nested-Loop Join Algorithm
1 Nested-Loop Join Algorithm
简单的Nested-Loop算法意思就是,从第一张表读取一条记录,然后与第二张表的每一行进行循环比对,达成表连接目的,然后再从第一张表读取一条记录与第二张表的每一条进行比对,如此往复,有几张表就有基层Nested-Loop循环。
举个例子如下:
现在使用Nested-Loop连接方式连接t1、t2、t3
Table Join Type
t1 range
t2 ref
t3 ALL
如果使用简单的NLJ算法,则会按如下方式处理连接:
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
}
}
}
2 Block Nested-Loop Join Algorithm
块嵌套循环(BNL)连接算法使用外部循环中读取的行的缓冲来减少必须读取内部循环中的表的次数。 例如,如果将10行读入缓冲区并将缓冲区传递给下一个内部循环,则可以将内部循环中读取的每一行与缓冲区中的所有10行进行比较。 这将内表必须读取的次数减少一个数量级。
MySQL join缓存具有以下特征:
- join_buffer_size变量决定buffer大小。
- 只有在join类型为all, index, range的时候才可以使用join buffer。
- 能够被buffer的每一个join都会分配一个buffer, 也就是说一个query最终可能会使用多个join buffer。
- 第一个nonconst table不会分配join buffer, 即便其扫描类型是all或者index。
- 在join之前就会分配join buffer, 在query执行完毕即释放。
- join buffer中只会保存参与join的列, 并非整个数据行。
bnl公式如下
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
}
}
empty join buffer
}
}
}
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
224/5000
随着join_buffer_size的值增加,t3扫描的数量减少,直到join_buffer_size足够大以容纳所有先前的行组合的点。 在那时,通过使其变大不会获得加速。