注册
达梦数据库表关联理解与测试
专栏/技术分享/ 文章详情 /

达梦数据库表关联理解与测试

雪糕い冰淇淋 2025/08/22 61 0 0
摘要

1.背景
本文主要阐述达梦表关联的相关概念以及达梦优化器什么时候使用不同的关联方法进行两表的关联的测试。旨在理解不同的表关联方式会有什么样的效果。
2.概述
表关联查询在数据库的SQL语句中存在非常普遍,在常见的关系型数据库中,主要存在三种形式的表关联,分别是:嵌套循环连接、哈希连接、归并排序连接,在达梦数据库中,支持对于表的三种关联方式,主要表关联形式是:
NEST LOOP
HASH JOIN
MERGE JOIN
NEST LOOP连接、哈希连接、归并排序连接方式在执行计划中均有相应的操作符进行标识,例如:
NEST LOOP INNER JOIN
NEST LOOP INDEX JOIN
HASH INNER JOIN
MERGE INNER JOIN
3.具体概念
对于以上的三种连接方式,在何种场景下会使用,执行的原理进行说明:
3.1.NEST LOOP
此种连接方式主要使用于被连接的数据子集较小的情况,NEST LOOP其实现原理就是扫描一个较小的表(称为驱动表或者外表,当然,也可以是根据查询条件筛选后的数据量较小),每读一条记录,就根据join字段上的索引去另外一张大表(称为被驱动表或者内表)里面查找所有符合join条件的记录,直到驱动表的数据全部查询完成,过程中,驱动表返回多少记录,就需要循环扫描大表多少次,所以必须保证驱动表返回记录较少,并且被驱动表的join列必须有索引。直到两个表的查询都完成,返回结果集进行展示或者传递给其他关联表,继续其他的表关联。这种查询的特点决定了其使用场景如下:
1、驱动表很小或者过滤条件很好,只返回少量的数据
2、被驱动表连接条件可以很好的使用索引
3、结果集比较小
3.2.HASH JOIN
Hash join通常使用在大数据集的两表关联时,关联列不存在索引、索引无法使用、或者优化器认为索引列过滤条件有限不能很好的筛选数据等情况下,都会使用hash join,分为两个阶段:构造HASH表阶段和扫描匹配阶段。
通常会选择两个表中较小(相对较小,不是绝对值,我们称为左表)的表中每行数据经过散列函数计算放到不同的hash槽中,形成hash表,然后将另一张数据量较大的表(我们称为右表)的join列经过散列函数计算后与前一个较小表形成的hash表进行匹配,匹配则返回相应的数据行。
选择左表构造HASH表的原因在于左表需要申请内存区域以构造hash表,如果选择右表构建hash表,则需要花费更大的代价,另外右表只需要做一次扫描,不需要构造hash表。所以综合来看,选择左表构造hash表更合适。
经过前面的说明,HASH JOIN需要通过散列函数对左表数据构造HASH表,在并发较大的系统中,对CPU、内存等系统资源消耗较大。
3.3.MERGE JOIN
Merge join在表关联中使用较少,此种关联首先需要确保两个关联表都是按照关联字段排序,再从每个表取一条记录进行匹配,如果符合关联条件,则放入结果集中,否则将关联字段值较小的记录抛弃,从这条记录对应的表中取下一条记录继续进行匹配,直到整个循环结束。
通过上面的理论描述,可以确认这三种连接方式在执行过程中,优化器如何选择连接方式,在统计信息准确的情况下,主要取决于以下因素:
1、需要查询数据的数据大小(存在表比较大,但是通过查询条件的筛选,所以需要根据筛选后的数据量大小来决定连接顺序)
2、连接列是否有索引
3、连接列是否需要进行排序
4.达梦默认两表关联测试
这个章节主要是测试默认情况下(即不人为干预),达梦优化器什么时候使用不同的关联方法进行两表的关联。
4.1.准备测试数据
本机准备了两个基础表,两个表分别插入20万行记录,并对表进行统计信息收集。
DROP TABLE T1;
DROP TABLE T2;
CREATE TABLE T1(C1 INT ,C2 INT,C3 VARCHAR(20) ,C4 VARCHAR(20) );
CREATE TABLE T2(C1 INT ,C2 INT,C3 VARCHAR(20) ,C4 VARCHAR(20) );
INSERT INTO T1 SELECT LEVEL C1,DBMS_RANDOM.RANDOM C2,DBMS_RANDOM.RANDOM_STRING(‘X’,20),DBMS_RANDOM.RANDOM_STRING(‘a’,20) FROM DUAL CONNECT BY LEVEL<=200000;
INSERT INTO T2 SELECT LEVEL C1,DBMS_RANDOM.RANDOM C2,DBMS_RANDOM.RANDOM_STRING(‘X’,20),DBMS_RANDOM.RANDOM_STRING(‘a’,20) FROM DUAL CONNECT BY LEVEL<=200000;
commit;
create index ind_t1_c1 on t1(C1);
create index ind_t2_c1 on t2(C1);
call SYS.DBMS_STATS.GATHER_TABLE_STATS(‘SYSDBA’,‘T1’,null,100,TRUE,‘FOR ALL COLUMNS SIZE AUTO’);
call SYS.DBMS_STATS.GATHER_TABLE_STATS(‘SYSDBA’,‘T2’,null,100,TRUE,‘FOR ALL COLUMNS SIZE AUTO’);
image.png

4.2.测试内容
4.2.1.嵌套循环连接验证
explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1=10;
image.png

此时是先使用索引对T1表进行扫描,再根据关联列,使用索引对T2表进行扫描,最后再进行nest loop的inner操作。从执行计划的内容可以看出,在关联列是等值条件及筛选条件只有一条记录的情况下,会选择使用nest loop inner join2进行两表关联。

4.2.2.归并排序连接验证
explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1<10;

对于关联列等值且关联列具有索引的情况下,由于索引本身已对C1列进行ASC排序,优化器预估仅需处理8行,同时归并连接的条件之一就是有序性,此时会选择使用merge join的方式进行两表关联。
image.png

4.2.3.哈希连接验证
explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1<10000;

对于关联列等值且关联列具有索引的情况下,由于索引本身已对C1列进行ASC排序,优化器预估需处理9998行,此时相较于t1.C1<10,过滤性明显变差,优化器会选择使用hash join的方式进行两表关联。
image.png

4.2.4.无索引情况下的执行计划
删除索引:
drop INDEX IND_T1_C1;
drop INDEX IND_T2_C1;
image.png

explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1=10;

从执行计划可以看出,在没有索引以及关联列是等值条件及筛选条件只有一条记录的情况下,会选择使用nest loop inner join2进行两表关联。但是两表都走了全表扫描,代价以及返回的结果集明显增大。
image.png

explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1<10;

对于关联列等值,t1.C1<10的过滤条件,由于走了全表扫描,预估处理的结果集大。代价以及返回的结果集都很大。优化器会选择使用hash join的方式进行两表关联。
image.png

explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C1<10000;

走的是全表扫描,代价以及返回的结果集增大。优化器会选择使用hash join的方式进行两表关联。
image.png
explain select * from t1 inner JOIN t2 on t1.C1>t2.C1 and t1.C1<10;

在非等值连接,t1.C1<10的情况下,会使用nest loop inner join的方式进行两表有关联。其中即便t1.C1<10预估处理的结果集少,但是t1.C1>t2.C1代价大,仍然是nest loop inner join。通过小表驱动大表进行扫描。
image.png

4.2.5.在等值连接中,过滤条件为非关联列
explain select * from t1 inner JOIN t2 on t1.C1=t2.C1 and t1.C2=215789235;
当and后面的过滤条件不为关联列时,此时由于C2列没有索引,走的是全表扫描。t1.C2=215789235走的是嵌套循环连接。t1.C1=t2.C1走的是哈希连接。
image.png

4.2.6.总结
经过以上的测试,发现达梦优化器在默认情况下,对关联或筛选在不同条件下的默认关联方式都存在不同。
测试结果如下:
具有索引:
1、在关联列是等值条件及筛选条件只有一条记录的情况下时,将会使用nest loop inner join方式表连接;
2、对于关联列等值且关联列具有索引,后续的过滤条件好的情况下,将会使用merge inner join方式进行表连接;
3、对于关联列等值且关联列具有索引,后续的筛选条件较差时的情况下,将会使用hash inner join方式进行表连接;
不具有索引:在没有索引的情况下,其代价和预估的结果集都明显增大,不管走什么连接,都是性能比较差的执行计划。
在等值连接中,过滤条件为非关联列时,如果非关联列为等值筛选条件且没有索引,则非关联列筛选条件走的是嵌套循环连接,外层的关联列走的是哈希连接。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服