MySQL 数据在连接缓冲区是怎么存储的?
MySQL 连接缓冲区(Join Buffer)是用于提升多表连接查询的速度的,连接查询的执行简化逻辑如下:
- 从存储引擎中读取
驱动表
的中的记录,把满足条件的记录存入连接缓冲区 - 当连接缓冲区满时,循环从存储引擎读取
被驱动表
的记录 - 每读取一条
被驱动表
的记录,遍历临时存放到连接缓冲区中的驱动表
的记录 - 判断
被驱动表
和驱动表
的记录是否匹配,如果匹配,且被驱动表是连接操作的最后一个表,则把匹配的记录发送给客户端(只发送客户端需要的字段)
上面的流程中提到了需要把驱动表的记录存入连接缓冲区,那么记录在连接缓冲区中是怎么存储的呢?
接下来会分为 3 个部分进行说明:
- 缓冲区链表
- 缓冲区中一条记录的组成
- 表中字段内容的存储格式
1. 缓冲区链表
当一条包含 JOIN 的连接语句中只包含 2 个表时,只会有一个缓冲区;如果包含 N 个表(N > 2),则会有 N - 1 个缓冲区,N - 1 个缓冲区会组成缓冲区链表
- 每个缓冲区都会有 prev cache 和 next cache 指针
- prev cache 指向前一个缓冲区
- next cache 指向后一个缓冲区
- 第一个缓冲区的 prev cache 指针为 NULL
- 最后一个缓冲区的 next cache 指针为 NULL
缓冲区链表示意图如下:
举个例子说明往连接缓冲区写入数据的过程:
假设有 t1、t5、t4、t3 四个表进行连接查询,执行计划中表的顺序也是 t1、t5、t4、t3,在连接执行过程中,有 3 个连接缓冲区:t5 表的缓冲区、t4 表的缓冲区、t3 表的缓冲区,执行时是把驱动表的记录放入被驱动表的缓冲区,执行流程如下:
- 从存储引擎读取 t1 表(
驱动表
)的数据,把符合 WHERE 条件(这一步只会判断 WHERE 条件,不会判断 ON 连接条件)的记录写入 t5 表的连接缓冲区(t5 表相对于 t1 表是被驱动表
) - t5 表的连接缓冲区满(
被 t1 表的记录填满了
),然后从存储引擎读取 t5 表的记录 - 每读取一条 t5 表中的记录,
判断该记录是否符合 WHERE 条件,不符合则继续从存储引擎读取t5
表的下一条记录
如果符合 WHERE 条件,则从 t5 表的连接缓冲区读取一条t1
表的记录,然后判断 t1 表的记录和 t5 表的记录是否匹配,不匹配则继