资讯专栏INFORMATION COLUMN

SQL优化之子查询展开

IT那活儿 / 797人阅读
SQL优化之子查询展开

点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!


  
发现一个SQL执行了半个小时,结果还没出来,找到我们帮忙分析优化一下。
这是一个典型的子查询被展开导致sql执行计划变差的案列。sql语句中三张表a、b、c关联查询,b和c表在外面,a在in里面。



 调优过程


原始SQL如下:

SELECTDISTINCTCASE
WHEN REGEXP_LIKE(B.REGISTERORGID, .XM) THEN
SUBSTR(B.REGISTERORGID,
1,
INSTR(B.REGISTERORGID, .XM, 1) - 1)
ELSE
B.REGISTERORGID
END,
B.SERVNUMBER,
C.RECOPID,
C.RECDATE,
B.SUBSID
FROM TBCS.SUBSCRIBER PARTITION(SUBSCRIBER_724) B,
TBCS.RECEPTION PARTITION(RECEPTION_724_202202) C
WHERE B.NETTYPE = GSM
AND B.ACTIVE = 1
AND B.STATUS = US10
AND B.CREATEDATE > TO_DATE(20220201, YYYYMMDD)
AND B.REGISTERORGID LIKEHB.JM.03.%
AND C.SERVNUMBER = B.SERVNUMBER
AND C.RECDATE > TO_DATE(20220201, YYYYMMDD)
AND C.RECDEFID = Install
AND B.SUBSID NOTIN
(SELECT  A.SUBSID
FROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) A
WHERE A.PRODID LIKEG238354%
AND A.APPLYDATE > TO_DATE(20220201, YYYYMMDD)
UNIONALL
SELECT  A.SUBSID
FROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) A
WHERE A.PRODID = MP9990103000300
AND A.APPLYDATE > TO_DATE(20220201, YYYYMMDD)
UNIONALL
SELECT/*+ index(a IDX_SUBS_PRODUCT_PRODID) */
A.SUBSID
FROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) A
WHERE A.PRODID IN (SELECT D.PRODID
FROM TBCS.PRODUCT D
WHERE D.PRODNAME LIKEXX%XXX%
OR D.PRODNAME LIKEXX%XXX%
OR D.PRODNAME LIKEXX%XXX%%
OR D.PRODNAME LIKEXX%XXX%%
OR D.PRODNAME LIKE%XX%
OR D.PRODNAME LIKE%XX%)
AND A.APPLYDATE > TO_DATE(20220201, YYYYMMDD))
ORDERBYCASE
WHEN REGEXP_LIKE(B.REGISTERORGID, .XM) THEN
SUBSTR(B.REGISTERORGID, 1, INSTR(B.REGISTERORGID, .XM, 1) - 1)
ELSE
B.REGISTERORGID
END,
C.RECDATE;
SQL整理完成后在adg上进行测试,发现在执行过程中产生gc cr request等待事件,执行很长时间结果也出不来。
在多带带把子查询SQL拿出来执行发现not in里面的SQL运行的非常快不到一秒就完成,但是联合B表一起执行的时候就非常慢,也产生了gc cr request等待。
此时多带带把B,C表关联查询不要not in发现结果只有5000多行,如下:
如此来看可以尝试让B,C优先关联,关联完成后再去not in里面与A的结果进行过滤,子查询不展开。
在子查询里面加入no_unnest的hint后一分钟即出现结果:
修改前执行计划如下:
修改后执行计划如下:



 分析总结


子查询展开(Subquery Unnesting)是优化器处理带子查询的目标sql的一种优化手段。

它是指优化器不再将目标sql中子查询当作一个独立的处理单元来多带带执行,而是将该子查询转换为它自身和外部查询之间等价的表连接。
这种等价连接转换要么是将子查询展开(即将该子查询中的表,视图从子查询中拿出来,然后和外部查询中的表,视图做表连接),要么是不拆开但是会把该子查询转换为一个内嵌视图(Inline View)然后再和外部查询中的表,视图做表连接。
子查询展开通常都会提高原sql的执行效率,因为如果原sql不做子查询展开,那么通常情况下该子查询就会在其执行计划的最后一步才被执行,并且会走filter类型的执行计划,这也就意味着对于外部查询所在结果集的每一条记录,该子查询就会被执行多少次。
在此次sql优化中,外部B、C表关联后结果集很小,且子查询里面sql全部走的索引,尝试子查询不展开,用B、C关联后的结果集去关联子查询,效率明显提升
由此可见,子查询展开并不一定会提高sql执行效率,是否展开,依据不同的情况进行选择。

本文作者:袁 钢(上海新炬王翦团队)

本文来源:“IT那活儿”公众号

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/129420.html

相关文章

发表评论

0条评论

IT那活儿

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<