我有一个查询,表示不同日期的行为不同。查询中的Filer条件如下所示
Last_Update_Date>TO_DATE(SUBSTR('#BIAPPS.LAST_EXTRACT_DATE',0,19),'YYYY-MM-DD HH24:MI:SS')
变量#BIAPPS.LAST_EXTRACT_DATE
的值从应用程序传递,数据类型为#BIAPPS.LAST_EXTRACT_DATE
的字母数字。
如果传递给#BIAPPS.LAST_EXTRACT_DATE
的值为2017-12-20 00:00:00
,则此查询将在10分钟内提取200条记录。
如果传递给#BIAPPS.LAST_EXTRACT_DATE
的值为2018-01-02 00:00:00
,则此查询将在120分钟内提取80K记录。
Oracle的行为如此,我是否需要更正?
答案 0 :(得分:1)
我的猜测是,在第一种情况下,它在LAST_EXTRACT_DATE使用索引,而在第二种情况下则不是。 (另一种猜测是,反之亦然,没有索引的查询实际上更快。)
诊断问题的最佳第一步是查看两个查询的执行计划。如果您不知道如何操作,可以在此处找到与其相关的问题。 SQLPlus中的快速方法是SET AUTOTRACE TRACEONLY EXPLAIN。
我假设您的意思是您正在对此查询模板进行文本替换,因此从Oracle解析器的角度来看,它们是两个不同的查询。您的问题的一个可能的解决方案是使用绑定变量,因此解析器将两者视为相同的查询并使用相同的执行计划。 (至少,它可能会;在最近的Oracle版本中,同一个查询可能会有更多变化。)但是,这个可能会导致您在更多情况下获得“糟糕”的执行计划例。
根据您使用最近日期的事实,可能的根本原因是此表上的统计信息已在相关的两个日期之间的某个时间收集。因此,解析器可以根据记录的列统计信息和/或直方图很好地估计第一个查询将返回多少条记录;但是对于第二个查询,它需要进行外推,因为日期超出了统计中记录的值范围。 (我在以前的系统中看到了很多。)
在这种情况下,另一种可能的解决方案是每晚显式刷新该表的统计信息。如果查询使用今天的日期,这可能无济于事,但如果所有查询在今天之前使用日期,则可能效果很好。
还有各种方法可以强制/指导Oracle使用所需的执行计划。老式的是明确的暗示。在这种情况下,如果我的第一个猜测是正确的,您可以在查询中添加INDEX提示。多年来,Oracle已经添加了许多功能来帮助解决这个问题。我认为当前的主要版本称为“SQL计划管理”,因此您可以对其进行研究。