注册
动态SQL与静态SQL的不同表现
专栏/滴水藏海/ 文章详情 /

动态SQL与静态SQL的不同表现

yuao 2021/12/31 2479 9 0
摘要 举例说明一个SQL在预编译和非预编译下执行耗时的性能差距原因

在一个项目中遇到这样一种情况,一个查询SQL在静态SQL和动态SQL下执行性能相差了10倍,那我们分析一下为什么有这么大差距吧!
由于最终结果集只有299行,为了精确获得服务端执行的时间,我们将FIRST_ROWS和设置为300,客户端工具取消分页显示,让SQL查询计算出所有结果。

表是有几百个字段的宽表,主键为PRIMARY KEY(I_STARTTIME,TYPE,PID,PERIOD,M_TYPE,M_STARTTIME)

首先来看静态SQL执行情况:
执行耗时1秒309毫秒
图片1.png
查看执行计划数据扫描方式为主键索引定位,分别用到了前两个字段的条件:
图片2.png
通过trace 10053可以看到优化器已经将第一个条件I_STARTTIME的范围扫描优化为等值匹配了:
图片3.png

下面看一下动态SQL的执行情况:
我们还是将原始参数值使用绑定参数的方式传入进去执行,
执行耗时居然达到了13秒51毫秒
图片4.png

查看执行计划我们看到数据扫描方式也是通过主键索引定位,但不一样的是只用到了主键索引的第一个条件I_STARTTIME,后面的条件都是在回表之后再过滤的。这里其实很好理解,由于动态SQL在编译时并不知道参数值,而第一个条件是范围过滤,那么优化器无法使用后续的字段进行索引定位。
图片6.png
那同样是主键索引定位,怎么静态SQL与动态SQL执行时间相差这么大?这时我们应该想到主键索引前两个字段I_STARTTIME与TYPE的过滤性如何:

SQL> select count(*) from t_test where  TYPE            = 'DATABASE';
行号       COUNT(*)
---------- --------------------
1          54643
已用时间: 2.328(毫秒). 执行号:704.
SQL> select count(*) from t_test where   i_StartTime BETWEEN '2021-05-27 00:00:00' AND '2021-05-28 00:00:00';

行号       COUNT(*)
---------- --------------------
1          496117

已用时间: 68.300(毫秒). 执行号:705.

原来I_STARTTIME就没有过滤,而TYPE的能到1/10的过滤性。真相大白了,动态SQL下由于索引定位按照第一个字段要将几乎全表数据进行回表操作,而静态SQL通过前主键索引前两个字段进行定位,只需要将1/10的数据进行回表,两种情况下耗时可想而知。那么按照这个思路我们创建索引:

CREATE  INDEX IDX_T_TEST_1 ON T_TEST(TYPE ASC,I_STARTTIME ASC);

静态SQL:
图片9.png
图片10.png
动态SQL:
可以看出此时动态SQL计划是使用了前两个条件进行二级索引定位,执行时间也与静态SQL执行达到了同一水平。
图片11.png
图片12.png

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服