前言
达梦数据库的表连接方式总体可以按如下图片进行总结:
猜想
先看嵌套连接定义:
两张表进行非等值连接时会选择嵌套连接。相当于两张表进行笛卡尔集操作。此时,优化器会选择一张代价较小的表作为外表(驱动表),另一张表作为内表,外表的每条记录与内表进行一次连接操作。 |
这里我很奇怪为什么非等值连接会走嵌套连接?我一直认为嵌套连接适合于分页查询。
于是设计了一个小实验来捣蛋一下(cost值只在实验中显示,并不代表现实环境)。
设计实验
设计两个表:
create table a_seg as select * from dba_segments; create table a_ts as select * from v$tablespace; |
设计分页查询语句如下:
select * from ( select a.bytes,a.segment_name,b.name from a_seg a,a_ts b where a.tablespace_name=b.name --等值连接 and a.owner='SYS' order by 1 desc ) where rownum<=3; |
如上语句若是之列看执行计划是如下的:
1 #NSET2: [2, 1, 200] 2 #PRJT2: [2, 1, 200]; exp_num(3), is_atom(FALSE) 3 #PRJT2: [2, 1, 200]; exp_num(3), is_atom(FALSE) 4 #SORT3: [2, 1, 200]; key_num(1), is_distinct(FALSE), top_flag(1), is_adaptive(0) 5 #HASH2 INNER JOIN: [1, 1, 200]; KEY_NUM(1); KEY(A.TABLESPACE_NAME=B.NAME) KEY_NULL_EQU(0) 6 #SLCT2: [1, 4, 152]; A.OWNER = 'SYS' 7 #CSCN2: [1, 181, 152]; INDEX33555655(A_SEG as A) 8 #CSCN2: [1, 6, 48]; INDEX33555656(A_TS as B) |
如上确实走了hash join,但我们加上hints后再来看下:
explain select * from ( select /*+ use_nl(a,b) leading(a,b) */ a.bytes,a.segment_name,b.name from a_seg a,a_ts b where a.tablespace_name=b.name and a.owner='SYS' order by 1 desc ) where rownum<=3; 1 #NSET2: [8, 1, 200] 2 #PRJT2: [8, 1, 200]; exp_num(3), is_atom(FALSE) 3 #PRJT2: [8, 1, 200]; exp_num(3), is_atom(FALSE) 4 #SORT3: [8, 1, 200]; key_num(1), is_distinct(FALSE), top_flag(1), is_adaptive(0) 5 #SLCT2: [7, 1, 200]; A.TABLESPACE_NAME = B.NAME 6 #NEST LOOP INNER JOIN2: [7, 1, 200]; 7 #SLCT2: [1, 4, 152]; A.OWNER = 'SYS' 8 #CSCN2: [1, 181, 152]; INDEX33555655(A_SEG as A) 9 #CSCN2: [1, 6, 48]; INDEX33555656(A_TS as B) |
可以看到确实走了nest loop。
结论
如此之后得到的结论为:
- 虽然定义中写的很明确,但是正常情况下我们可以灵活修改。保证数据库走出最佳的执行计划。
- 若是没有hints,我们就可以在测试时看到执行计划是否异常。比如:这里应该走的是hash join,为什么现在是nest loop(没有hints的情况)?
- 嵌套连接还是适合走分页查询的,因为确实可以利用参数first_rows以达到最佳效果。
达梦数据库技术社区:https://eco.dameng.com