Oracle调优之no_unnest和unnest用法简介
本博客介绍Oracle SQL调优的一种常用也是很实用的方法,也即/*+no_unnest */
和/*+ unnest*/
,介绍Oracle 的 /*+unnest */
、 /*+ no_unnest */
之前,先介绍一下Hint。
Hint对于开发人员来说,可能不是很熟悉,但是对于DBA来说,Hint可是一种调优的利器,Hint 是Oracle 提供的一种SQL语法,是oracle早期因为oracle优化器还不是很完善加上去的,可以辅助oracle优化器,常用于SQL调优,通过Hint强行改变Oracle的执行计划,从而实现SQL调优
也就是说Hint语法可以人工地干预Oracle优化器选择执行计划,当然Hint虽然很实用,但是用的不好,也必然影响SQL性能,国内DBA大牛在其博文里就有曾提到,引用其博文的观点:
详情可以参考作者博文:https://dbaplus.cn/news-10-669-1.html
ok,有了前面的必要知识后,可以介绍一下Oracle的Hint语法之no_unnest和unnest用法了,no_unnest、unnest显然是一对相对的用法
- unnest:也即解嵌套,nest是嵌套的意思,也就是让子查询展开查询,和外部的查询进行关联、合并,从而得到执行计划
- no_unnest:双重否定表肯定,也是子查询嵌套(nest),让子查询不展开,这时候子查询往往是最后执行的,作为FILTER条件来过滤外部查询
对于hint语法来说,形式就是/*+ .... */
的形式,所以对于这两种嵌套和解嵌套查询,其用法分别为/*+ no_unnest */
、/*+ unnest*/
,加在子查询的select关键字后面即可,我之前博客曾经整理过Hint的常用语法,详情参考我博客Oracle之Hint用法整理笔录
案例记录,ok,最近遇到一个sql查询需要超过1分钟的情况,因为是生产环境问题,比较紧急,业务又特别复杂,SQL很复杂,关联了十几张表(业务需要),如果通过改写sql来调优,比较花时间,业务不够熟悉的情况,所以,首先我也是先通过加必要索引的方式,检查主键、外键是否都有索引了,索引也不能乱叫,还要分析哪些表更新比较多的,然后我是想到hint调优,虽然hint有局限性是在某些sql不改写的情况是可以起到作用的,如果sql改变,hint语法很有可能影响SQL性能,所以使用hint调优并非上策
我遇到的sql是很复杂的,不过本文进行简单描述,其SQL语法类似如下,省略很多的情况:
select id,....,from t1 left join t2 where t2.id in (select k from t1 where ...) ....
首先,我想到用子查询解嵌套方式,进行改写:
select id,....,from t1 left join t2 where t2.id in (select /*+ unnest */ k from t1 where ...) ....
然后通过执行计划查询,性能并没有提升,unnest是让子查询展开,和外部的查询进行关联、合并,首先t1是一张数据量很多的表,然后SQL里先left join了t1,又在子查询里使用了t1,如果unnest的话,不是会进行自连接?所以我改成/*+ no_unnest */
,不让子查询展开,让子查询最后执行,作为一个filter条件,经过实验,sql查询从1分钟以上都0点及秒
ok,说明一下,本人水平并没有dba水平,对于SQL调优没有丰富经验,所以请作者可以不管我的案例,只要理解unnest和no_unnest的用法即可,sql调优是很复杂,需要很多调优经验才可以做到游刃有余的,本博客观点,仅代表本人观点,因为对sql调优本没有深入理解,所以也并没有特别推崇使用unnest或者no_unnest,这两种用法具体在什么环境使用适宜?在网上也没有找到特别明确的说明,所以遇到sql性能问题,通过分析执行计划是最有用的
附录:
- SQL优化:一篇文章说清楚Oracle Hint的正确用法:https://dbaplus.cn/news-10-669-1.html
- 性能优化之查询转换 子查询类:https://chuansongme.com/n/1394222147942
- 解决CBO的SQL优化问题(图文详解):https://www.php.cn/mysql-tutorials-360101.html
- Oracle里的查询转换:https://www.linuxidc.com/Linux/2019-03/157808.html