在为我们的数据处理应用程序运行性能基准测试时,我们以FOO_TABLE为空,然后从一个线程插入记录,而在另一个线程中,我们使用如下查询从处理中选择相同的记录:
select * from FOO_TABLE where ID > ?
与:
结合使用stmt.setMaxRows(5000);
在Java中用来限制在一个块中选择的记录数。 (我们不想在这里使用BETWEEN,因为ID有间隙)。我们继续处理5000个块,直到测试停止。
现在,我们的应用程序的性能会随着时间的推移而降低,当我检查Oracle端发生的情况时,我很惊讶地注意到“select * from FOO_TABLE ID>?”的查询计划。执行表扫描而不是使用ID上的PK索引。
重新启动我们的应用程序(但没有截断表)后,Oracle回到原因并使用了PK索引。
所以,我的解释是,甲骨文认为扫描表几乎是空的时候是一个好主意,但后来从未修改过这个查询计划。这让我想到了一个问题:oracle多久修改一次查询计划?
是不是因为我重新启动了申请?我对此有一些疑问,因为我们在1小时后回收我们的汇集连接(因此没有连接可能超过1小时)。
是因为已经过了一段时间吗?
即使桌子几乎是空的,你怎么强迫oracle不进行扫描?
环境信息: - oracle 11g - jdbc client(java 6)
更新10/25/2011:我对Oracle 10g进行了回归测试,问题是相同的,因此动态游标共享既不会引起也不会修复它。正如马克最初提到的那样,除非有结构变化或重新计算表统计数据等重大事件,否则该计划不会得到修订。
最后我添加了一个提示以强制PK访问,但我认为优化器应该能够解决这个问题。如果有一个匹配搜索条件的PK,那么继续使用甚至小表(无论如何性能差异都是微不足道的。)
答案 0 :(得分:2)
什么版本的Oracle?
通常,
select * from FOO_TABLE where ID > ?
如果语句不在共享池中,将难以解析。这将是执行计划生成的时间。
之后,执行计划不会发生变化,除非导致其失效。 (删除/添加表的索引,从表中删除列,重新计算表上的统计数据等)。
11g具有自适应游标共享(这就是为什么我问过Oracle的版本),并且,在没有了解很多细节的情况下,它将查看绑定变量值并确定是否需要基于新的计划更改绑定值。
答案 1 :(得分:2)
我认为这是过时表统计信息的一种情况。除了自适应游标共享之外,Oracle只会在收集新统计信息时从优化程序角度查看新行。在此之后的某个时间,将生成一个新计划。
对于此查询,您使用的提示是无害的。通常最好解决潜在的问题,而不是暗示。第一行提示也可能在表达意图时起作用。
答案 2 :(得分:2)
如果由于您使用过时的统计信息而导致查询效率低下(如此处所示),则答案通常是重新收集统计信息。
您通常可以依赖Oracle来检测统计信息是否已过时并仅为相应的对象重新收集它们,但是如果启用了表监视,则还可以检查DBA_TAB_MODIFICATIONS以查看自统计信息以来是否发生了大量更改最后聚集。
如果您的表格在行数中频繁波动 - 例如在一个表格中存储批量数据以供以后处理 - 那么一个好的策略是删除并锁定表格的统计信息并依赖于优化器动态对要返回的行的估计进行抽样。
答案 3 :(得分:1)
自适应游标共享是优化器的内置功能,从11.1开始。您运行的是哪个版本的Oracle? (完整版本号?)我希望11g的更高版本,即11.2.0.2,11.2.0.3表现得更好。
关于自适应游标共享的细节的讨论可能超出了本论坛的范围,但是,请参阅此处以获得对它的良好讨论: http://blogs.oracle.com/optimizer/entry/update_on_adaptive_cursor_sharing
此外,请使用该博客上的搜索功能获取有关同一主题的更多帖子,以及许多其他优化器主题。该博客实际上是由Oracle的优化开发团队编写的,因此它是一个很好的资源。