设为首页 收藏本站
查看: 363|回复: 0

[经验分享] ORACLE使用WITH AS和HINT MATERIALIZE优化SQL解决FILTER效率低下

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-7-18 08:45:47 | 显示全部楼层 |阅读模式
在做项目的过程中,一个页面使用类似如下的SQL查询数据,为了保密和使用方便,我把项目中有关的表名和字段替换使用ORACLE数据库中的系统表和字段。

在我所做的项目中,类似ALL_TABLES的表中大概有8W多条数据,下面这个查询SQL很慢。


    WITH PARAMS AS  
     (SELECT '' USER_ID, '' SDATE, '%' || '' || '%' SNAME FROM DUAL)  
    SELECT AU.USERNAME, AU.USER_ID  
      FROM ALL_USERS AU  
     INNER JOIN PARAMS PA  
        ON 1 = 1  
     INNER JOIN DBA_USERS DU  
        ON AU.USERNAME = DU.USERNAME  
     WHERE ((PA.SDATE IS NULL AND PA.USER_ID IS NOT NULL AND  
           AU.USER_ID = PA.USER_ID) OR  
            
           (PA.SDATE IS NULL AND PA.USER_ID IS NULL AND  
           AU.USERNAME NOT IN  
           (SELECT AU.USERNAME  
                FROM ALL_USERS AU  
               INNER JOIN DBA_USERS DEV  
                  ON AU.USERNAME = DEV.USERNAME  
               INNER JOIN (SELECT OWNER AS USERNAME  
                            FROM ALL_TABLES T  
                           WHERE T.LAST_ANALYZED = TRUNC(SYSDATE)) ATA  
                  ON AU.USERNAME = ATA.USERNAME)) OR  
           (PA.SDATE IS NOT NULL AND  
           AU.USERNAME IN  
           (SELECT AU.USERNAME  
                FROM ALL_USERS AU  
               INNER JOIN DBA_USERS PA  
                  ON AU.USERNAME = PA.USERNAME  
               INNER JOIN ALL_TABLES ATA  
                  ON PA.USERNAME = ATA.OWNER  
               WHERE TO_CHAR(ATA.LAST_ANALYZED, 'YYYY-MM-DD') = PA.SDATE) AND  
           AU.USER_ID = PA.USER_ID))  
       AND DU.PROFILE LIKE 'D%'  
       AND AU.USERNAME LIKE PA.SNAME  

针对上面的SQL语句执行慢的问题,我做了如下的分析:


                第一步,把语句的WHERE条件后的三个OR都分别和主查询一块执行,执行速度都很快,放到一块就很慢。


                第二步,对比上面SQL和三个OR拆分出来的三个SQL的执行计划,如下图所示。发现上面SQL的执行中有一个FILTER,过滤器谓词中用到了NOT EXISTS,是导致这条SQL跑的慢的原因。

SouthEast.jpg


原因找到了,就得想办法把执行计划的FILTER去掉。开始想加HINT,但是实验了很多HINT,都不起作用。最后的结果还一样,后来想到WITH AS 能提高SQL的查询速度,就把影响SQL执行的那段SQL放到WITH AS里面,结果还是一样。后来尝试把HINT MATERIALIZE和WITH AS 结合使用,修改成如下的SQL,查询速度立即提升了很多。如下图所示,执行计划中FILTER的NOT EXISTS不存在了。

    WITH PARAMS AS  
     (SELECT '' USER_ID, '' SDATE, '%' || '' || '%' SNAME FROM DUAL),  
    USERNAMEDATA AS  
     (SELECT /*+ materialize */  
       AU.USERNAME  
        FROM ALL_USERS AU  
       INNER JOIN DBA_USERS DEV  
          ON AU.USERNAME = DEV.USERNAME  
       INNER JOIN (SELECT OWNER AS USERNAME  
                    FROM ALL_TABLES T  
                   WHERE T.LAST_ANALYZED = TRUNC(SYSDATE)) ATA  
          ON AU.USERNAME = ATA.USERNAME)  
    SELECT AU.USERNAME, AU.USER_ID  
      FROM ALL_USERS AU  
     INNER JOIN PARAMS PA  
        ON 1 = 1  
     INNER JOIN DBA_USERS DU  
        ON AU.USERNAME = DU.USERNAME  
     WHERE ((PA.SDATE IS NULL AND PA.USER_ID IS NOT NULL AND  
           AU.USER_ID = PA.USER_ID) OR  
            
           (PA.SDATE IS NULL AND PA.USER_ID IS NULL AND  
           AU.USERNAME NOT IN (SELECT USERNAME FROM USERNAMEDATA)) OR  
           (PA.SDATE IS NOT NULL AND  
           AU.USERNAME IN  
           (SELECT AU.USERNAME  
                FROM ALL_USERS AU  
               INNER JOIN DBA_USERS PA  
                  ON AU.USERNAME = PA.USERNAME  
               INNER JOIN ALL_TABLES ATA  
                  ON PA.USERNAME = ATA.OWNER  
               WHERE TO_CHAR(ATA.LAST_ANALYZED, 'YYYY-MM-DD') = PA.SDATE) AND  
           AU.USER_ID = PA.USER_ID))  
       AND DU.PROFILE LIKE 'D%'  
       AND AU.USERNAME LIKE PA.SNAME  


SouthEast.jpg

总结:

在FILTER中,NOT EXISTS后的SQL语句多次执行,本来数据量就很大,每次都要执行一遍,结果可想而知。但是使用HINT MATERIALIZE和WITH AS 结合使用,把内联视图实体化,执行过程中会创建基于视图的临时表。这样就不会每次NOT EXISTS都去执行一遍大数据表的扫描,只需要扫描一次即可。

但是是不是可以在WITHAS中的每个语句都实体化那?如果WITH AS中的语句只被调用一次的话,最好还是不要使用HINT MATERIALIZE,因为使用HINT MATERIALIZE第一次查询会创建基于视图结果的临时表,这也耗费一些时间。多次使用的话可以使用HINT MATERIALIZE。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-22206-1-1.html 上篇帖子: RMAN深入解析之--BlockRecover恢复坏块 下篇帖子: ORACLE常用系统查询
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表