1. 本际云推荐 - 专业推荐VPS、服务器,IDC点评首页
  2. 云主机运维
  3. VPS运维

SQL优化之子查询展开

SQL优化之子查询展开

你好,我是本际云服务器推荐网的小编小本本,在SQL优化中,我们常常会遇到子查询展开导致SQL执行计划变差的情况。以下是一个典型案例。

SQL优化之子查询展开

一段SQL语句中涉及三张表a、b、c的关联查询,其中b和c表在外面,a在in里面。原始SQL如下:

SELECT DISTINCT 
    CASE 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.SUBSCRIBERPARTITION(SUBSCRIBER_724) B, 
     TBCS.RECEPTIONPARTITION(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 LIKE HB.JM.03.% 
AND   C.SERVNUMBER = B.SERVNUMBER 
AND   C.RECDATE > TO_DATE(20220201, YYYYMMDD) 
AND   C.RECDEFID = Install 
AND   B.SUBSID NOT IN (
                   SELECT A.SUBSID 
                   FROM   TBCS.SUBS_PRODUCTPARTITION(SUBS_PRODUCT_724) A 
                   WHERE  A.PRODID LIKE G238354% 
                   AND    A.APPLYDATE > TO_DATE(20220201, YYYYMMDD) 
                   UNION ALL 
                   SELECT A.SUBSID 
                   FROM   TBCS.SUBS_PRODUCTPARTITION(SUBS_PRODUCT_724) A 
                   WHERE  A.PRODID = MP9990103000300 
                   AND    A.APPLYDATE > TO_DATE(20220201, YYYYMMDD) 
                   UNION ALL 
                   SELECT /*+index(aIDX_SUBS_PRODUCT_PRODID)*/ A.SUBSID 
                   FROM   TBCS.SUBS_PRODUCTPARTITION(SUBS_PRODUCT_724) A 
                          ,TBCS.PRODUCTD D 
                   WHERE  A.PRODID IN (
                                       SELECT D.PRODID 
                                       FROM   TBCS.PRODUCTD 
                                       WHERE  D.PRODNAME LIKE XX%XXX% 
                                       OR     D.PRODNAME LIKE XX%XXX% 
                                       OR     D.PRODNAME LIKE XX%XXX%% 
                                       OR     D.PRODNAME LIKE XX%XXX%% 
                                       OR     D.PRODNAME LIKE %XX% 
                                       OR     D.PRODNAME LIKE %XX%
                                     ) 
                   AND    A.APPLYDATE > TO_DATE(20220201, YYYYMMDD)
                  )
ORDER BY CASE WHEN REGEXP_LIKE(B.REGISTERORGID, '.XM') THEN SUBSTR(B.REGISTERORGID, 1, INSTR(B.REGISTERORGID, '.XM', 1) - 1) ELSE B.REGISTERORGID END, C.RECDATE;

在测试SQL的执行过程中,我们发现在执行过程中产生gccrrequest等待事件,执行很长时间结果也无法出来。进一步拆分SQL查询,我们发现notin里面的SQL具有非常快的运行速度(不到1秒就完成),但是联合B表一起执行的时候就非常慢,也产生了gccrrequest等待。多带带把B、C表关联查询并不执行notin,得到结果只有5000多行,如下:

SQL优化之子查询展开

结合以上情况,我们可以尝试让B、C表优先进行关联查询,关联完成后再去notin里面与A的结果进行过滤,避免子查询展开。在子查询里面加入no_unnest的hint后一分钟即出现结果。修改前的执行计划如下:

SQL优化之子查询展开

修改后的执行计划如下:

SQL优化之子查询展开

分析总结

子查询展开(Subquery Unnesting)是优化器处理带子查询的目标SQL的一种常见优化手段。它是指优化器将目标SQL中的子查询转换为它自身和外部查询之间等价的表连接。这种等价连接转换可将子查询展开,将该子查询中的表和视图从子查询中拿出来,然后和外部查询中的表和视图做表连接,也可将该子查询转换为一个内嵌视图(Inline View)然后再和外部查询中的表和视图做表连接。

子查询展开通常会提高SQL执行效率,因为如果原SQL不做展开,该子查询通常会在其执行计划的最后一步才被执行,并且会走filter类型的执行计划,这也就意味着对于外部查询所在结果集的每一条记录,该子查询就会被执行多少次。

在本次SQL优化中,外部B、C表通过关联查询得到的结果集比较小,且子查询中的SQL全部走了索引,因此我们可以尝试不展开子查询,用B、C关联后的结果集去关联子查询。对于不同情况下的SQL优化,我们应该根据实际情况选择是否展开子查询来提高SQL执行效率。

更多有关SQL优化的内容,请关注“IT那活儿”公众号。

原创文章,作者:小编小本本,如若转载,请注明出处:https://www.benjiyun.com/yunzhujiyunwei/vps-yunwei/6388.html