我正在运行一个查询,该查询返回特定日期范围之间的月份对象集合。查询工作正常,但速度非常慢(在本地计算机上约为2秒,在企业开发环境中约为30秒)。这是:
SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) AS MONTH
FROM all_objects
WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) <= TO_DATE('200805', 'YYYYMM')
目前,它只返回一个月,但如果你扩展第二个日期字符串,它会返回更多。
我有两个问题。首先,为什么这么慢?我知道Oracle函数确实会减慢查询速度,但在我的工作中,这需要大约30秒才能在开发计算机上完成。
第二个也是一个令人费解的问题:为什么当你将范围扩展到'201805'时,运行时会缩短到几分之一秒?我认为更大的范围需要更长的时间。这似乎是相反的效果。
答案 0 :(得分:4)
请改用
SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) AS MONTH
FROM (select level rn from dual connect by level < 4000)
WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) <= TO_DATE('200805', 'YYYYMM')
;
这可以避免在两个环境之间可能存在差异的all_object。
all_objects是一个复杂的视图,因此不会像上面使用的内联视图那样高效。如果您不想使用“connect by”语法,则创建一个整数表并使用它。
答案 1 :(得分:3)
使用MONTHS_BETWEEN()函数消除任意4000个月限制的Janek函数的轻微变体
SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) AS MONTH
FROM ( select level rn
from dual
connect by level < abs(months_between(TO_DATE('200804', 'YYYYMM'),TO_DATE('201805', 'YYYYMM')))+2
)
WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) <= TO_DATE('201805', 'YYYYMM')
;
答案 2 :(得分:2)
无需使用内联视图,我看到使用了太多日期函数。 如果你跳过这一切,这仍然是:
SQL> var START_YM varchar2(6)
SQL> var END_YM varchar2(6)
SQL> exec :START_YM := '200804'; :END_YM := '201805'
PL/SQL procedure successfully completed.
SQL> select add_months(to_date(:START_YM,'yyyymm'),level-1) m
2 from dual
3 connect by level <= months_between(to_date(:END_YM,'yyyymm'),to_date(:START_YM,'yyyymm'))+1
4 /
M
-------------------
01-04-2008 00:00:00
01-05-2008 00:00:00
01-06-2008 00:00:00
<... 116 rows skipped ...>
01-03-2018 00:00:00
01-04-2018 00:00:00
01-05-2018 00:00:00
122 rows selected.
看起来更容易......
此致 罗布。
答案 3 :(得分:0)
这里的部分困难是它需要为ALL_OBJECTS视图中的每一行评估ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum)
。如果你重写where子句,它将使用另一个COUNT STOPKEY而不是COUNT的计划。
请尝试以下查询。我的运行速度要快得多。
SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) AS MONTH
FROM all_objects
where
months_between(date '2008-05-01, date '2008-04-01') >= rownum
您使用201805进行查询以使查询运行得更快的评论实际上是错误的。查询运行速度不快,只会让第一行恢复得更快,所以看起来更快。
结束日期设置为2008-05-01,它需要在返回任何行之前直接遍历整个ALL_OBJECTS表,但是如果时间较长,则在缓冲区已满时将返回行。每个查询将在相同的时间内完成运行。