# SQL优化之子查询展开

> 作者/来源: UCloud 运营管理员
> 发布时间: 2023-01-11T05:19:00.000Z
> 分类: 其他
> 原文链接: http://117.50.162.249:3000/yun/articles/1463

---

# SQL优化之子查询展开

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

SQL优化之子查询展开

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

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_000.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_001.png)

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

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

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_010.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_011.png)

**调优过程**

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_012.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_013.png)

**原始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多行，如下：**

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_006.png)

如此来看可以尝试让B,C优先关联，关联完成后再去not in里面与A的结果进行过滤，子查询不展开。

在子查询里面加入no\_unnest的hint后一分钟即出现结果：

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_007.png)

修改前执行计划如下：

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_008.png)

修改后执行计划如下：

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_009.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_010.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_011.png)

**分析总结**

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_012.png)

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_013.png)

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

它是指优化器不再将目标sql中子查询当作一个独立的处理单元来多带带执行，而是将该子查询转换为它自身和外部查询之间等价的表连接。

这种等价连接转换要么是将子查询展开（即将该子查询中的表，视图从子查询中拿出来，然后和外部查询中的表，视图做表连接），要么是不拆开但是会把该子查询转换为一个内嵌视图（Inline View）然后再和外部查询中的表，视图做表连接。

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

**在此次sql优化中**，外部B、C表关联后结果集很小，且子查询里面sql全部走的索引，尝试子查询不展开，**用B、C关联后的结果集去关联子查询，**效率明显提升。

由此可见，子查询展开并不一定会提高sql执行效率，是否展开，依据不同的情况进行选择。

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_014.png)

## 本文作者：袁 钢（上海新炬王翦团队）

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

![](https://ucloud-blog.cn-bj.ufileos.com/articles/129420/images/129420_015.png)