SQL优化之子查询展开

AI 摘要 / TL;DR

SQL优化之子查询展开 点击上方“IT那活儿 ”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!! 发现一个SQL执行了半个小时,结果还没出来,找到我们帮忙分析优化一下。 这是一个典型的子查询被展开导致sql执行计划变差的案列。 sql语句中三张表a、b、c关联查询,b和c表在外面,a在in里面。 调优过程

来源: https://www.ucloud.cn/yun/129420.html 作者: IT那活儿 发布日期: 发布于2023-01-11 13:19

SQL优化之子查询展开

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

发现一个SQL执行了半个小时,结果还没出来,找到我们帮忙分析优化一下。

**这是一个典型的子查询被展开导致sql执行计划变差的案列。**sql语句中三张表a、b、c关联查询,b和c表在外面,a在in里面。

调优过程

原始SQL如下:

SELECTDISTINCTCASEWHEN REGEXP_LIKE(B.REGISTERORGID, .XM) THENSUBSTR(B.REGISTERORGID,1,INSTR(B.REGISTERORGID, .XM, 1) - 1)ELSEB.REGISTERORGIDEND,B.SERVNUMBER,C.RECOPID,C.RECDATE,B.SUBSIDFROM TBCS.SUBSCRIBER PARTITION(SUBSCRIBER_724) B,TBCS.RECEPTION PARTITION(RECEPTION_724_202202) CWHERE B.NETTYPE = GSMAND B.ACTIVE = 1AND B.STATUS = US10AND B.CREATEDATE > TO_DATE(20220201, YYYYMMDD)AND B.REGISTERORGID LIKEHB.JM.03.%AND C.SERVNUMBER = B.SERVNUMBERAND C.RECDATE > TO_DATE(20220201, YYYYMMDD)AND C.RECDEFID = InstallAND B.SUBSID NOTIN(SELECT  A.SUBSIDFROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) AWHERE A.PRODID LIKEG238354%AND A.APPLYDATE > TO_DATE(20220201, YYYYMMDD)UNIONALLSELECT  A.SUBSIDFROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) AWHERE A.PRODID = MP9990103000300AND A.APPLYDATE > TO_DATE(20220201, YYYYMMDD)UNIONALLSELECT/*+ index(a IDX_SUBS_PRODUCT_PRODID) */A.SUBSIDFROM TBCS.SUBS_PRODUCT PARTITION(SUBS_PRODUCT_724) AWHERE A.PRODID IN (SELECT D.PRODIDFROM TBCS.PRODUCT DWHERE 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))ORDERBYCASEWHEN REGEXP_LIKE(B.REGISTERORGID, .XM) THENSUBSTR(B.REGISTERORGID, 1, INSTR(B.REGISTERORGID, .XM, 1) - 1)ELSEB.REGISTERORGIDEND,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那活儿”公众号