暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

关于表关联关联条件中存在or的一次优化

原创 杜伟 2023-07-04
584

在生产系统上发现个sql执行需要十几个小时,查看monitor的瓶颈在于一个结果集被作为视图参与nest loop,被当做被驱动表执行了n次

生产上的语句较为复杂,剔除了其他表关联,我用自己的环境模拟了这个场景create table dw_0704 as select * from dba_objects;

create table dw_0704a as select * from dba_objects where rownum <10000;

--写法1
select *
  from dw_0704a a
  left join dw_0704 b
    on a.object_id = b.object_id
   and ((b.object_name like 'D%' and b.namespace = 1) or
       (b.object_type like 'T%' and b.namespace = 4) or
       (b.created > to_date('20230101', 'yyyymmdd') and b.namespace = 4))

--写法2
select *
  from dw_0704a a
  left join (SELECT *
               FROM dw_0704 b
              WHERE (b.object_name like 'D%' and b.namespace = 1)
                 or (b.object_type like 'T%' and b.namespace = 4)
                 or (b.created > to_date('20230101', 'yyyymmdd') and
                    b.namespace = 4)) D
    on a.object_id = D.object_id

比较下两次执行的效果以及执行计划,我们采用sql monitor收集真实的执行计划,用hint强制采集,/*+ monitor dwtest92 */

select * from v$sql where sql_text like '%dwtest92%';          --查看sql_id

select dbms_sqltune.report_sql_monitor(sql_id=>'2r7jww7j05rv8',type=>'HTML',report_lEVEL=>'ALL') AS REPORT FROM DUAL;       ---查询monitor报告

写法1的报告:


可以看出执行消耗了47s,采用的是嵌套循环链接方式,dw_0704被执行了9999次全表扫描,总cost是惊人的300w;

第二种写法报告:


可以看到耗时很短,0.2s多,采用的是hash链接方式,dw_0704被执行了一次,总cost是385;

对于以上的优化总结,left join (select * from t where name like 'new%') x on x.id=a.id ; 等价于:left join t on t.id=a.id and t.name like 'new%';

建议使用left join (select * from t where name like 'new%') x on x.id=a.id ; 当on后面的条件复杂例如存在多个or的时候,该执行计划很可能是走嵌套循环连接,如果这个表比较大

此时就是悲剧加上悲剧;部分情况下,On 后面的条件不复杂时,执行计划是跟(left join (select * from t where name like 'new%') x on x.id=a.id ;)写法的执行计划一样的。所以,

在实际情况中还是要多测试观察真实的执行计划,督促开发设计减少使用or,以及关联表的数量,建议不要超过3个。



最后修改时间:2023-10-18 08:53:58
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论