oracle优化之大表连接小表,从1小时到5秒的优化实战
数据库:oracle 11
起因:生产环境突然收到告警,一条很简单的sql执行了1个小时。需要对这条sql进行优化。
sql如下:

其中T1表每天数据量为 2000条,T0每天数据200W条。T1的PERIOD_NO、BATCH_DATE有单独字段的索引,T0的PERIOD_NO单独索引、BATCH_DATE和CHANNEL_CODE有单独字段的索引。
PS:表中的所有where查询条件都有索引了,而且T1(小表)内连接T0(大表)。
通过表面现象来看,一切都是那么的完美,小白说:哪里有一点问题嘛,这要我优化个锤子哦,该有的字段全部有索引了。再慢老子也没办法。
那我们看看执行计划吧,是不是真的那么完美

执行计划出来了,那先科普怎么看吧。
口诀:从右往左,从上往下。 所以正确的执行顺序是:5->4->6->7->3->2->1->0
0123这几个步骤没啥可看的。
看看5做了什么:

把大表进行筛选走了联合索引,大约筛选出了200W数据。
4做了什么:

根据索引做了一下回表操作。
6做了什么:

把小表做了一下筛选,大约筛选出了2000条数据
7做了什么:


通过T0(大表)连接T1(小表),连接字段走了小表的索引。
总结下以上步骤:1、对大表通过联合索引做了下筛选(200w)2、回表、3、对小表通过batch_date索引做了下筛选(2000) 4、通过大表结果集去关联小表结果集,走小表的关联索引。
这这这.....这不是操蛋吗?为啥是通过200W数据集去关联2000的结果集,这可是要遍历200w次啊,问题查到了。怎么改呢?
优化:
任何优化都要有思路,那么我们期望的执行计划应该是怎样的呢?
1、对小表通过batch_date索引做了下筛选(2000) 2、回表 3、对大表通过联合索引做了下筛选(200w) 4、通过小表结果集去关联大表结果集,走大表的关联索引。
思路:小表去关联大表,走大表的关联索引。那么我们可以原来的sql上加上强制索引来纠正执行计划。
优化后的sql,强制走T0的关联索引:

看看优化后的执行计划:

执行顺序:5->4->6->7
5做了什么:

走了小表的索引筛选结果(2000条)
4做了什么?
就是回表
6做了什么?


通过T1小表来关联大表TO,这里别被上图误导了,哪个表作为主导表关联要看哪张表在执行计划上面,如图:

先回表的是小表,根据小表的PERIOD_NO的值去大表索引遍历查询,过滤数据。
7做了什么:


根据关联好的数据集去筛选数据,回表。(PS:flter不一定会使用联合索引)。
总结以上所做的事:1、走了小表的索引筛选结果2、回表 3、通过T1小表来关联大表TO 4、根据关联好的数据集去筛选数据
如果关联好的数据集较小的情况下不走索引比走索引效率更改。所以现在的执行计划是完美的,符合预期的。
final上线:
1小时----------->5秒

浙公网安备 33010602011771号