转载

一个执行计划解析的小问题分析

前几天,一个开发的同学让我帮忙做一个大查询,给了我一个数据列表,里面的ID有几万个,提供了一个SQL语句,看这情况还得我自己来解析生成相关的SQL了。
假设ID列表为:
T100
T200
T300
SQL语句为:
select peak_transaction_id,cash ,req_time  ,back_time  from peak_new.peak_detail where peak_transaction_id=?;
对我来说拼成动态SQL也是分分钟,但是这种方式不推荐,还是推荐使用数据的结果集方式来匹配。
所以我可以根据id拼接成insert语句,或者直接使用外部表来关联。表里只有一个字段id varchar2(30)
在运行语句之前我还是会照例来查看执行计划,如果太差我就提前想别的办法了。
执行计划着实让我大跌眼镜。一个简单的键值关联的语句,执行计划竟然如此的查,来看看瓶颈在哪里。
一个执行计划解析的小问题分析
可以从谓词信息看出,里面做了数据类型的转换,根据ID这个字段值数据类型应该是varchar2,是不需要转换为number类型的。
但是通过执行计划看出,内部是做了数据类型的转换,最后这种关联方式的消耗竟然如此惊人。
我就感觉有些蹊跷,为什么会有这种差别,按理来说是不需要这种类型转换啊。
调用的SQL语句如下:
select TEST_transaction_id,cash ,req_time  ,back_time  from TEST_new.TEST_detail where TEST_transaction_id in (select id from tempdba.test);
发现问题的症结在于tempdba.test不是我刚刚创建的临时表,而是指向了一个已经存在的表。这个表的结构如下:
一个执行计划解析的小问题分析

所以这个问题就有点意思了,tempdba.test虽然和属主下的表test同名,但是字段完全不同,在生成执行计划的时候竟然还能成功,这个也让人着实怀疑优化器处理执行计划是不是也有很多不足之处。
我使用了正确的schema之后,重新生成执行计划,这一次得到的预估结果还是在接受范围之内。我完全可以在备库去跑这个查询实现目标。
一个执行计划解析的小问题分析
那么问题来了,是不是执行计划对于字段的校验存在疏漏呢,我们来简单测试几个小例子。
发现在常见的表关联中还是能够校验出来的。
一个执行计划解析的小问题分析
再来看看exists的方式是否也有问题。发现也是可以检测出来的。
一个执行计划解析的小问题分析
所以再回头看这个问题,就会发现在最开始的语句中。
select TEST_transaction_id,cash ,req_time  ,back_time  from TEST_new.TEST_detail where TEST_transaction_id in (select id from tempdba.test);
采用in的子查询的时候,对于子查询中的列可以和关联的表不同名,我们可以取别名来达到的兼容的目的,我想正是如此在执行计划中也会弱化了这方面的检查,严格来说,姑且算是一个bug吧。

正文到此结束
Loading...