oracle多久修改一次查询计划?



当我们为数据处理应用程序运行性能基准测试时,我们从一个线程的FOO_TABLE开始,然后从一个线程插入记录,而在另一个线程中,我们使用如下查询从处理中选择相同的记录:

select * from FOO_TABLE where ID > ?

结合:

stmt.setMaxRows(5000);

来限制在一个块中选择的记录的数量。(我们不想在这里使用BETWEEN,因为id有间隙)。并且我们继续处理5000个块,直到测试停止。

现在,我们的应用程序的性能随着时间的推移而下降,当我检查Oracle端发生的情况时,我惊讶地注意到"select * from FOO_TABLE where ID> ?"的查询计划进行了表扫描,而不是在ID上使用PK索引。

重新启动我们的应用程序后(但没有截断表),Oracle恢复理智,使用了PK索引。

所以,我的解释是,Oracle认为扫描表是一个好主意,当它几乎是空的,但后来从未修改过这个查询计划。这就引出了我的问题:oracle多久修改一次查询计划?

是因为我重新启动了应用程序吗?我对此有一些疑问,因为我们在1小时后回收我们的池连接(因此没有连接可以超过1小时)。

是因为一段时间过去了吗?

如何强制oracle在表几乎为空的情况下不进行扫描?

环境信息:- oracle 11g- JDBC客户端(java 6)

UPDATE 10/25/2011:我在Oracle 10g上做了一个回归测试,问题是相同的,所以它既不是由动态游标共享引起的,也不是由动态游标共享修复的。正如Mark最初提到的,除非发生结构变化或重新计算表统计等重大事件,否则不会修改计划。

最后我添加了一个提示,通过PK强制访问,但我认为优化器应该能够发现这一点。如果存在匹配搜索条件的PK,那么即使在小表中也要继续使用(无论如何,性能差异是微不足道的)。

什么版本的Oracle?

,

select * from FOO_TABLE where ID > ?
如果语句不在共享池中,

将难以解析。这将是生成执行计划的时间。

之后,执行计划不会改变,除非有什么原因导致它无效。(删除/添加一个索引到表中,从表中删除一个列,重新计算表上的统计,等等)

11g具有自适应游标共享(这就是我询问Oracle版本的原因),并且,在不涉及太多细节的情况下,它将查看绑定变量值并根据新的绑定值确定是否需要更改计划。

我认为这是一个陈旧的表统计的情况。除了自适应游标共享之外,当收集到新的统计信息时,Oracle只会从优化器的角度看到新的行。一段时间后,将生成一个新的计划。

对于这个查询,您使用的提示是无害的。通常最好是解决潜在的问题,而不是暗示。

第一行提示在表达意图时也可能有效。

如果由于使用过时的统计数据而导致查询效率低下,那么解决方法通常是重新收集统计数据。

您通常可以依靠Oracle来检测统计数据是否过时,并仅为适当的对象重新收集统计数据,但是如果表监控打开,您也可以检查dba_tab_modified,以查看自上次收集统计数据以来是否发生了大量更改。

如果你的表在行数上波动非常频繁——例如在一个表中,为以后的处理阶段批量数据——那么一个好的策略是删除和锁定表的统计数据,并依靠优化器动态采样来估计要返回的行。

自适应游标共享是从11.1开始的优化器的内置特性。您运行的是什么版本的Oracle ?(完整版本号?)我希望以后的11g版本,即11.2.0.2、11.2.0.3的性能会更好。

关于自适应光标共享的来龙去脉的讨论可能超出了本论坛的范围,但是,在这里可以看到一个很好的讨论:http://blogs.oracle.com/optimizer/entry/update_on_adaptive_cursor_sharing

同时,使用该博客上的搜索功能查找同一主题的更多文章,以及许多其他优化器主题。这个博客实际上是由Oracle的优化器开发团队写的,所以它是一个很好的资源。

最新更新