oracle sql 全是子查询查询速度太慢如何优化_SQL之美第四篇:谓词推入巧妙优化SQL...

本次给大家带来的是 ORACLE 巧妙使用谓词推入优化SQL。直入正题:

       本周,开发反馈跑批速度太慢,申请优化并提供了相关SQL,该SQL是一条标准的insert* select插入语句,去除无关的部分,SQL如下:

2b5527f0a641dbd3ca00706cdce34c45.png

业务需求,5秒以内,查看执行计划:

aaf59a18a303e0bae7b2f7ad783eafd2.png

发现 MCR_BILL_M表与CAP_OVERDUE_HIS表走了谓词推入,CAP_OVERDUE_HIS表与MCR_BILL_D表走了全表扫描。

我们知道,当SQL语句包含不能合并的视图同时视图有谓词过滤也就是where过滤条件的时候,CBO会将谓词过滤条件推入视图,这就是谓词推入。这里MX表就是成功走了连接列谓词推入,但是TER表却失败了。

首先,查看TB表数据量:

3a0363e54efb4a3da87931aec444afa8.png

仅仅170条,看来MX表谓词推入的效果是成功的(原因最后会解释),再检查TER内部两个表的字段过滤性,发现这两个表结果集分别是1100W,33W,占据源表95%以上数据量,走索引是没戏了,表面看 确实就是最优计划了,有的人看到这里会说:结果集差异那么大,为什么不走NL呢?

是的,一般情况下确实走NL会快很多,但是各位注意到没有:

b75b2516e5e5bfd702f813c1ab74c2eb.png

这个count(*)太致命,无法走NL,CAP_OVERDUE_HIS表还是得走全表扫描,如下图所示:

2f2e01f2dd0ff42f5bcda683e61c5ca0.png

最终必须要hash做group,那么到这里基本就需要分析SQL的本质了。

既然MX能够谓词推入成功,那么使用 push_pred强行推入谓词到TER表中是否可以呢?

下面让我们来做下实验:

ef681ec179fa5047276fad8d26e9b0ef.png

整整32秒才出来结果!再看执行计划:

1df66c3a0e3d9157ce3144af8f3dbc57.png

很明显,谓词虽然推入成功了,但是这个千万级大表CAP_OVERDUE_HIS的全表扫描没有避免,整体效率没有得到提升。无法谓词推入,源表也没有好的过滤方式,到这里,我们就不能纠结TER内部逻辑了,总览整个SQL发现

关键信息:

37df4d630f590b35df803f0ebfcb4e93.png

可知TB表是主表,而且总体只有170条数据,左连接的概念相信各位都知道,既然取的以TB表为准,那么,我们可以强行把TB表写入TER表里面,手动推入如下:

4ef3c9cf30ff0a7f8356bfa6a8a38e43.png

优化成功!秒杀效果!观察执行计划:

a93180a2a02934a19619ee304da0584d.png

果然推入成功!不过各位注意到没有前面MX表的谓词推入标识没了,这里它走了常量谓词推入(观察7的谓词条件可知PR被推入视图)。

这里我们将插入的TB表作为驱动,在不改变整体取数逻辑的情况下强行驱动了TER内部两个表,这才是谓词推入的意义:帮助ORACLE尽可能过滤无用的数据。

实际生产中,经常遇到谓词推入引发的性能问题,有说谓词推入好的也有坏的,众说纷纭,那么,为什么谓词推入是好是坏呢?

我们要明白其本质,下面做个简单说明:

常量谓词推入(非连接列推入)基本对于性能的提升都是有益处的(相信CBO的判断)。

连接列谓词推入经常引发性能问题,因为连接列谓词推入需要传值(传入视图内),有传值操作的表连接只有NL或者FILTER。

FILTER专门针对半连接或者反连接,即where后面包含的子查询语句,

而谓词推入专门针对from后面的子查询,所以连接列谓词推入,被推入的视图一般都是NL的被驱动表。

所以,如果驱动表ROWS过大以及CBO估算失误算的过小,就会导致被推入的视图扫描次数过多,总耗时比原来反而多了。

通过本案例,对于这块的理解更加深刻了,在此发出来,与众君共勉,如有问题,欢迎指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值