【StoneDB Class】入门第五课:StoneDB 中的表连接

本次课程为大家讲述 StoneDB 中的表连接。StoneDB 的表连接方式有 Nested Loop Join、Sort Merge Join、Map Join、Hash Join,不同的连接方式有不同的使用场景,在 StoneDB 中使用最广泛的是 Map Join 和 Hash Join。下面为大家详细介绍上述提到的四种表连接方式。

image.png

Nested Loop Join

通过一个示例来理解 Nested Loop Join 的原理:

mysql> select count(*) from t1,t2 where t1.id <> t2.id and t1.last_name='八';
+----------+
| count(*) |
+----------+
|  9999998 |
+----------+
1 row in set (28.90 sec)

假设优化器会选择表 t1 为驱动表,表 t2 为被驱动表,Nested Loop Join 的执行过程如下:

1)遍历驱动表的结果集,取出结果集中的第1条记录;

2)遍历被驱动表的结果集,按照关联字段去判断被驱动表的结果集中是否存在匹配的记录,如果匹配成功,则返回数据,否则就被丢弃;

3)直到遍历完驱动表的结果集为止。

从执行过程可知,驱动表有多少结果集,被驱动表就需要扫描多少次。如果驱动表的结果集很大,被驱动表就要扫描很多次,SQL 的性能就会非常的差。在其它数据库中,如果表连接方式是 Nested Loop Join,且被驱动表的关联字段是索引字段,那么 Nested Loop Join 还是很高效的。但在 StoneDB 中,即使表连接的关联条件是等值查询,且被驱动表的关联字段是索引字段,优化器也不会选择 Nested Loop Join,而选择 Hash Join 或者 Map Join。

Nested Loop Join 的使用场景:多表关联的连接字段是非等值查询。

要想知道表与表之间进行关联使用的是哪种表连接方式,需要设置参数 tianmu_control_trace,然后查看 trace.log,trace.log 的默认保存路径在 log 目录下。

set global tianmu_control_trace=1;--SQLset global tianmu_control_trace=0;
more /stonedb57/install/log/trace.log
image.png
image.png

Sort Merge Join

通过一个示例来理解 Sort Merge Join 的原理:

mysql> select count(*) from t3,t4 where t3.id > t4.id and t3.last_name='八';
+---------------+
| count(*)      |
+---------------+
| 1618433818772 |
+---------------+
1 row in set (4.93 sec)

在多表关联返回较大数据量时,Nested Loop Join 存在性能问题,因此出现了 Sort Merge Join,Sort Merge Join 的执行过程如下:

1)根据谓词条件访问其中的一张表,得到的结果集按照表中的连接字段排序,排好序的结果集记为结果集 R1;

2)根据谓词条件访问另外一张表,得到的结果集按照表中的连接字段排序,排好序的结果集记为结果集 R2;

3)遍历结果集 R1,即取出结果集R1中的第1条记录去和结果集 R2 中按照连接字段判断是否存在匹配的记录,直到遍历完结果集 R1 中所有的记录。

从执行过程可知,Sort Merge Join 需要对连接字段进行排序,我们知道在数据库中做排序是比较消耗资源的,如果无法使用内存排序,那么就需要使用磁盘排序,磁盘排序会生成临时文件,导致大量 IO 和空间占用等问题。在未出现 Hash Join 之前,Sort Merge Join 是处理大数据较为理想的表连接方式。

Sort Merge Join 的使用场景:多表关联的连接字段出现大于、小于比较。

image.png
image.png

Hash Join

通过一个示例来理解 Hash Join 的原理:

mysql> select count(*) from t2,t3 where t2.first_name=t3.first_name;
+---------------+
| count(*)      |
+---------------+
| 1303595576856 |
+---------------+
1 row in set (2.46 sec)

向右滑动代码

假设优化器会选择表 t2 为驱动表,表 t3 为被驱动表,Hash Join 的执行过程如下:

1)在内存中建立 hash table,根据 hash 函数计算出表 t2 结果集中关联字段的 hash value,将计算出的 hash value 存放到内存的 hash table;

2)根据 hash 函数计算出表 t3 结果集中关联字段的 hash value;

3)表 t3 结果集中关联字段的 hash value 与内存中的 hash table 进行匹配,如果匹配成功,则返回数据,否则就被丢弃。

从执行过程可知,每张表只需要扫描一次,hash 函数可以把 hash value 均匀地打散,匹配的效率还是非常高效的。

Hash Join 的使用场景:多表关联返回大量数据,且连接字段必须是等值查询。

image.png
image.png

Map Join

通过一个示例来理解 Map Join 的原理:

mysql> select count(*) from t2,t3 where t2.id = t3.id;
+----------+
| count(*) |
+----------+
|  5000000 |
+----------+
1 row in set (14.49 sec)

mysql> set global tianmu_force_hashjoin=on;
Query OK, 0 rows affected (0.01 sec)
mysql> select count(*) from t2,t3 where t2.id = t3.id;
+----------+
| count(*) |
+----------+
|  5000000 |
+----------+
1 row in set (2.40 sec)

Map Join 的执行过程与 Hash Join 的执行过程很相似,通常情况下 Hash Join 算法比 Map Join 高效,如果把参数 tianmu_force_hashjoin 打开,原本优化器选择的表连接方式是 Map Join,现在会选择 Hash Join。

image.png

以上是本次课程的全部内容,感谢各位继续关注。

StoneDB官网: https://stonedb.io/

Github: https://github.com/stoneatom/stonedb

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容