前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SQL优化案例-使用with as优化Subquery Unnesting(七)

SQL优化案例-使用with as优化Subquery Unnesting(七)

原创
作者头像
沃趣科技
发布2018-10-31 14:28:01
7370
发布2018-10-31 14:28:01
举报
文章被收录于专栏:沃趣科技

使用 no_unnest hint可以让执行计划产生filter,即不展开,但一般情况下使用unnest hint无法消除filter。

如下SQL,找出库中非唯一索引,那么大家可能会这么写SQL:

代码语言:javascript
复制
SELECT SEGMENT_NAME,SUM(BYTES/1024/1024) m FROM DBA_SEGMENTS WHERE SEGMENT_NAME 
NOT IN (select index_name from dba_indexes where UNIQUENESS ='NONUNIQUE') GROUP BY SEGMENT_NAME;

耗时一分钟,为什么这么慢呢?在SQL语句where子查询后有not in、not exists、in、exists时,CBO会尝试将子查询展开(unnest)消除filter,但是上面的例子CBO并没有做到,下面我们看下执行计划。

我们再看下在子查询中加unnest hint的执行计划:

代码语言:javascript
复制
SELECT SEGMENT_NAME,SUM(BYTES/1024/1024) m FROM DBA_SEGMENTS WHERE
SEGMENT_NAME  NOT IN (select /*+UNNEST */index_name from dba_indexes
where UNIQUENESS ='NONUNIQUE') GROUP BY SEGMENT_NAME;

filter消除,CBO将基于数据字典底层的基表重新组合,使执行计划变成hash joinanti,0.23秒便执行完成了。

下面我们再来看下通过with as materialize优化subquery unnesting的例子。

SQL如下:

代码语言:javascript
复制
select  AREA_NAME,sum(reve)
from t_order o 
where exists (select AREA_ID
        from t_customer c
       where nation = 'Aus'
         and c.AREA_ID = o.AREA_ID
      union
      select AREA_ID
        from f_customer f 
      where nation = 'US'
        and f.AREA_ID <> o.f_area_id) group by AREA_NAME;
代码语言:javascript
复制
selectsum(bytes/1024/1024) M from dba_segments where segment_name ='F_CUSTOMER';

    M
----------
    192

表F_CUSTOMER192M

执行计划如下:

我们看到并不走索引,要近2个小时执行完成,通过建立组合索引,让其走index_ffs

代码语言:javascript
复制
CREATE INDEX IDX_FFS_NATION_ID ONf_customer(AREA_ID,nation,0);

8分钟执行完成,那么还有没有更好的办法呢?

如下:

代码语言:javascript
复制
with x as ( select /*+ materialize */ AREA_ID from f_customer f 
      where nation = 'US') 
select  AREA_NAME,sum(reve)
from t_order o 
where exists (select AREA_ID
        from t_customer c
       where nation = 'Aus'
         and c.AREA_ID = o.AREA_ID
      union
      select AREA_ID
        from x where x.AREA_ID <> o.f_area_id) group by AREA_NAME;

在FILTER中,NOT IN(NOT EXISTS)后的SQL语句多次执行,本来数据量就很大,每次都要执行一遍,结果可想而知。但是使用HINT MATERIALIZE和WITH AS 结合使用,把表中部分列实体化,执行过程中会创建基于视图的临时表。这样就不会每次NOT EXISTS都去执行一遍大数据表的扫描或者大的索引快速扫描,并且当表的数据越大,表越宽,这样的优化效果越明显。

| 作者简介

姚崇·沃趣科技高级数据库技术专家

熟悉Oracle、MySQL数据库内部机制,丰富的Oracle、MySQL故障诊断、性能调优、数据库备份恢复、复制、高可用方案及迁移经验。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • | 作者简介
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档