达梦数据库(简称DM)查询中,in\exists子查询分两种:in\not in、exists\not exists。子查询的连接分四种情况:XNLP、HNLP、SNLP、SMRG。下面首先简单介绍一下达梦数据库in\exists子查询,然后对每种连接情况进行分析。
1、 in\exists查询
形如:(left expression)exists (select_sub_expression )
(left expression)in (select_sub_expression )
上面两条语句为in\exists子查询,两种方式的执行过程有些差别。执行EXISTS子查询,数据库系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项。执行IN子查询,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。
举例进行说明:
以下是引用片段: create table t1(c1 int,c2 int); create table t2(d1 int,d2 int); insert into t1 values(1,1); insert into t1 values(2,2); insert into t2 values(1,1); insert into t2 values(2,2); |
(1)exists查询
select * from t1 where exists ( select * from t2 where d1>c1)
执行计划为:
以下是引用片段: #RSET:[0, 0, 0]; #XFLT:[0, 0, 0]; IsGreatZero(Expr3) #XNLP:[0, 0, 0]; CROSS_JOIN #CSEK:[0, 0, 0]; INDEX33556678(t1), FULL_SCAN #XRCS:[0, 0, 0]; #XFLT:[0, 0, 0]; EXPR2 > EXPR0 #CSEK:[21, 1, 1]; INDEX33556647(t2), FULL_SCAN |
分析:由于t1表没有建立索引,首先对t1表进行全表扫描,接着从t1表中取出一条记录与t2表中的记录进行比较,直到找到第一条满足d1>c1,输出t1表当前记录,否则,从t1表中取第二条记录重复上面操作,直到t1表记录扫描完毕。
(2)in查询
select * from t1 where c1 in (select d1 from t2)
执行计划为:
以下是引用片段: #RSET:[21, 1, 1]; #XFLT:[0, 0, 0]; IsGreatZero(Expr2) #XNLP:[0, 0, 0]; CROSS_JOIN #CSEK:[21, 1, 1]; INDEX33556678(t1), FULL_SCAN #XRCS:[0, 0, 0]; EXPR0 = EXPR3 #TTS:[0, 0, 0]; tmp_table(unsorted) #CSEK:[0, 0, 0]; INDEX33556647(t2), FULL_SCAN |
分析:由于t2表没有索引,首先对t2表进行全表扫,取出d1列较较 from t2)建立临时表,接着从t1表逐条取记录,与临时表进行比较,最后将满足c1=d1的记录输出。
以上是对达梦数据库中简单的exists\in子查询的分析,复杂的子查询与此原理相同,过程会有些差别。下面分别对子查询中的四种连接情况进行分析。
1) 子查询连接情况分析
由于exists和in查询的连接情况类似,因此下面以exists和in为例穿插进行分析。
(1) XNLP
XNLP操作符的含义是在查询中连接左右两子查询,或者在cross join的连接类型下顺次完成左儿子和右儿子操作符运行。
例如:
以下是引用片段: create table t1(c1 int,c2 int); create table t2(d1 int,d2 int); select * from t1 where exists ( select * from t2 where d1 |