2

我需要获取特定工作日的某些特定时间数据,回到 10 周。我工作的数据库是 Oracle。我想出了以下带有时间戳字段的条件:

TO_CHAR(hy.tstamp,'HH24')='10' 
AND hy.tstamp > sysdate - 70  
AND mod(extract ( day from sysdate-1) - extract ( day from hy.tstamp), 7) =0 

有人告诉我“绝对没有围绕 tstamp 的功能”(出于性能原因?)。您将如何指定没有对时间戳字段进行操作的条件?

4

2 回答 2

4

这听起来就像抱怨性能的人从未听说过基于函数的索引。

Create index char_hy_stamp on my_table(to_char(hy.tstamp,'HH24'));

这应该避免全表扫描,这无疑是您解释计划的一部分。一旦你的 sqlfiddle 运行起来,我们就可以从那里开始。

于 2013-05-08T19:51:41.917 回答
2

如果您加入可接受范围的表,则可以过滤掉没有函数或函数索引的时间片。您可以像这样动态创建一个(请注意,您需要这些函数来创建表,但之后您将不再需要它们):

SELECT
  TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '10' HOUR AS StartAt,
  TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '11' HOUR AS EndAt
FROM DUAL
CONNECT BY LEVEL <= 10

今天的日期是 2013 年 5 月 8 日,这将为您提供以下信息:

STARTAT             ENDAT
------------------- -------------------
05/07/2013 10:00:00 05/07/2013 11:00:00
04/30/2013 10:00:00 04/30/2013 11:00:00
04/23/2013 10:00:00 04/23/2013 11:00:00
04/16/2013 10:00:00 04/16/2013 11:00:00
04/09/2013 10:00:00 04/09/2013 11:00:00
04/02/2013 10:00:00 04/02/2013 11:00:00
03/26/2013 10:00:00 03/26/2013 11:00:00
03/19/2013 10:00:00 03/19/2013 11:00:00
03/12/2013 10:00:00 03/12/2013 11:00:00
03/05/2013 10:00:00 03/05/2013 11:00:00

现在只需将其加入您的查询以获得所需的时间片,并注意您不需要函数:

WITH TimeRanges AS (
  SELECT
    TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '10' HOUR AS StartAt,
    TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '11' HOUR AS EndAt
  FROM DUAL
  CONNECT BY LEVEL <= 10
)
SELECT
  ... whatever ...
FROM your_table hy
INNER JOIN TimeRanges ON
  hy.tstamp >= TimeRanges.StartAt AND
  hy.tstamp < TimeRanges.EndAt

如果您的数据库人员了解时间戳函数过滤会降低性能(除非 Woot4Moo 指出,他们实现了函数索引),他们就会明白用于创建时间片表的函数不会影响更大的查询。

于 2013-05-08T20:30:34.890 回答