[英]How often does oracle revise a query plan?
当为我们的数据处理应用程序运行性能基准测试时,我们以FOO_TABLE为空开始,然后从一个线程插入记录,而在另一个线程中,我们使用如下查询从处理中选择相同的记录:
select * from FOO_TABLE where ID > ?
和这个结合:
stmt.setMaxRows(5000);
用Java来限制在一个块中选择的记录数。 (我们不想在这里使用BETWEEN,因为ID之间有空格)。 并且我们将继续处理5000个块,直到测试停止。
现在,我们的应用程序的性能会随着时间的推移而下降,当我检查Oracle方面发生了什么时,我惊讶地注意到查询计划为“ select * from FOO_TABLE where ID>?” 执行表扫描,而不使用ID上的PK索引。
重新启动我们的应用程序后(但不截断表),Oracle恢复了推理并使用了PK索引。
因此,我的解释是,Oracle认为在表几乎为空时扫描表是个好主意,但是从不修改此查询计划。 这使我想到了一个问题:甲骨文多久修改一次查询计划?
是因为我重新启动了应用程序吗? 我对此有一些疑问,因为我们在1小时后回收了池化连接(因此,任何连接都不得早于1小时)。
是因为一定时间过去了吗?
即使表几乎为空,您将如何强制oracle不执行扫描?
环境信息:-oracle 11g-jdbc客户端(java 6)
UPDATE 10/25/2011:我对Oracle 10g进行了回归测试,问题是相同的,因此它不是由动态游标共享引起的,也不是由固定的。 正如Mark最初提到的那样,除非发生结构变更或重新计算表格统计等重大事件,否则该计划不会得到修订。
最终,我添加了一个提示,以强制PK进行访问,但是我认为优化程序应该能够弄清楚这一点。 如果有一个与搜索条件匹配的PK,则继续使用甚至用于小型表(无论如何,性能差异都微不足道)。
我认为这是表统计数据过时的情况。 除了自适应游标共享之外,Oracle只会在收集新统计信息时从优化程序角度看到新行。 这种情况发生后的一段时间内,将生成一个新计划。
对于此查询,您使用的提示是无害的。 通常,最好是解决根本问题而不是提示。 在表达意图时,第一行提示也可能起作用。
如果查询由于您使用的是过时的统计信息而效率低下(如此处所示),那么答案通常是重新收集统计信息。
通常,您可以依靠Oracle来检测统计信息是否过时并仅对适当的对象进行收集,但是您也可以检查DBA_TAB_MODIFICATIONS是否打开了表监视功能,以查看自上次收集统计信息以来是否发生了大量更改。
如果您的表的行数波动非常频繁(例如,在一个表中分批批量数据以供以后处理),那么一个好的策略是删除并锁定表的统计信息,并依靠优化器动态采样来进行估计要返回的行。
什么版本的Oracle?
通常,
select * from FOO_TABLE where ID > ?
如果该语句不在共享池中,则将进行硬解析。 这将是生成执行计划的时间。
在那之后,执行计划将不会改变,除非有某种原因导致其无效。 (向表中添加/添加索引,从表中删除列,在表上重新计算统计信息,等等)。
11g具有自适应游标共享(这就是我询问Oracle版本的原因),并且无需深入了解,它就会窥视绑定变量值并根据新的绑定值确定是否需要更改计划。
从11.1开始,自适应游标共享是优化器的内置功能。 您正在运行什么版本的Oracle? (完整版本号?)我希望11g的更高版本(即11.2.0.2、11.2.0.3)表现得更好。
关于自适应游标共享的来龙去脉的讨论可能不在本论坛的讨论范围之内,但是,请参见此处,以获得有关它的良好讨论: http : //blogs.oracle.com/optimizer/entry/update_on_adaptive_cursor_sharing
另外,使用该博客上的搜索功能可以找到有关同一主题的更多帖子,以及许多其他优化程序主题。 该博客实际上是由Oracle优化程序开发团队撰写的,因此它是一个极好的资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.