常见的关联算法有三大类,分别是嵌套循环(Nested Loop Join)、排序归并(Sort-Merge Join)和哈希(Hash Join)。
嵌套循环连接算法
外层循环表称为外表(Outer 表),内层循环表则称为内表(Inner 表)。因为这个算法的过程是由遍历 Outer 表开始,所以 Outer 表也称为驱动表。
嵌套循环算法又可以细分为三种,分别是 Simple Nested-Loop Join(SNLJ)、Block Nested-Loop Join(BNJ)和 Index Lookup Join(ILJ)。
SNLJ 的执行过程是这样的:
- 遍历 Outer 表,取一条记录 r1;
- 遍历 Inner 表,对于 Inner 表中的每条记录,与 r1 做 join 操作并输出结果;
- 重复步骤 1 和 2,直至遍历完 Outer 表中的所有数据,就得到了最后的结果集。
BNJ 是对 SNLJ 的一种优化,改进点就是减少 Inner 表的全表扫描次数。BNJ 的变化主要在于步骤 1,读取 Outer 表时不再只取一条记录,而是读取一个批次的 x 条记录,加载到内存中。这样执行一次 Inner 表的全表扫描就可以比较 x 条记录。在 MySQL 中,这个 x 对应一个叫做 Join Buffer 的设置项,它直接影响了 BNJ 的执行效率。
Index Lookup Join(ILJ)就是在 BNJ 的基础上使用了索引,算法执行过程是这样的:
- 遍历 Outer 表,取一个批次的记录 ri;
- 通过连接键(Join Key)和 ri 可以确定对 Inner 表索引的扫描范围,再通过索引得到对应的若干条数据记录,记为 sj;
- 将 ri 的每一条记录与 sj 的每一条记录做 Join 操作并输出结果;
- 重复前三步,直到遍历完 Outer 表中的所有数据,就得到了最后结果集。
排序归并连接算法
排序归并算法就是 Sort-Merge Join(SMJ),也被称为 Merge Join。SMJ 可以分为排序和归并两个阶段:
- 第一阶段是排序,就是对 Outer 表和 Inner 表进行排序,排序的依据就是每条记录在连接键上的数值。
- 第二阶段就是归并,因为两张表已经按照同样的顺序排列,所以 Outer 表和 Inner 表各一次循环遍历就能完成比对工作了。
选择 SMJ 是有前提的,而这个前提就是表的记录本身就是有序的,否则就不划算了。我们知道,索引是天然有序的,如果表的连接键刚好是索引列,那么 SMJ 就是三种嵌套循环算法中成本最低的,它的时间复杂度只有 O(m+n)。
哈希连接算法
哈希连接的基本思想是取关联表的记录,计算连接键上数据项的哈希值,再根据哈希值映射为若干组,然后分组进行匹配。常见的哈希连接算法有三种,分别是 Simple Hash Join、Grace Hash Join 和 Hybrid Hash Join。
Simple Hash Join,也称为经典哈希连接(Classic Hash Join),它的执行过程包括建立阶段(Build Phase)和探测阶段(Probe Phase)。
- 建立阶段
选择一张表作为 Inner 表,对其中每条记录上的连接属性(Join Attribute)使用哈希函数得到哈希值,从而建立一个哈希表。在计算逻辑允许的情况下,建立阶段选择数据量较小的表作为 Inner 表,以减少生成哈希表的时间和空间开销。
2.探测阶段
另一个表作为 Outer 表,扫描它的每一行并计算连接属性的哈希值,与建立阶段生成的哈希表进行对比。当然,哈希值相等不代表连接属性相等,还要再做一次判断,返回最终满足条件的记录。
GHJ 算法与 SHJ 的不同之处在于,GHJ 正视了哈希表大于内存这个问题,将哈希表分块缓存在磁盘上。GHJ 中的 Grace 并不是指某项技术,而是首个采用该算法的数据库的名字。
第一阶段,Inner 表的记录会根据哈希值分成若干个块(Bucket)写入磁盘,而且每个 Bucket 必须小于内存容量。Outer 表也按照同样的方法被分为若干 Bucket 写入磁盘,但它的大小并不受到内存容量限制。
第二阶段和 SHJ 类似,先将 Inner 表的 Bucket 加载到内存,再读取 Outer 表对应 Bucket 的记录进行匹配,所有 Inner 表和 Outer 表的 Bucket 都读取完毕后,就得到了最终的结果集。
Hybrid Hash Join,也就是混合哈希,字面上是指 Simple Hash Join 和 Grace Hash Join 的混合。实际上,它主要是针对 Grace Hash Join 的优化,在内存够用的情况下,可以将 Inner 表的第一个 Bucket 和 Outer 表的第一个 Bucket 都保留在内存中,这样建立阶段一结束就可以进行匹配,节省了先写入磁盘再读取的两次 I/O 操作。
哈希连接算法不仅能够处理大小表关联,对提升大表之间关联的效率也有明显效果,但限制条件就是适用于等值连接。
分布式数据库
分布式数据库下关联算法的优化依赖于并行框架(MPP),而并行框架更多地出现在 OLAP 数据库中,不是分布式数据库的标配。
小表和大表关联:小表复制到大表节点中,有静态指定小表,需要人工干预;小表广播,不需要人工干预,系统自行处理。
大表关联:按照查询条件重分布。
shuffle 阶段:分别将两个表按照连接键进行分区,将相同连接键的记录重分布到同一节点,数据就会被分配到尽量多的节点上,增大并行度。
hash join 阶段:每个分区节点上的数据单独执行单机 hash join 算法。
此文章为6月Day20学习笔记,内容来源于极客时间《分布式数据库30讲》