【问题标题】:Oracle Index is not used when compare timestamp with <= or >=将时间戳与 <= 或 >= 进行比较时不使用 Oracle 索引
【发布时间】:2016-01-27 03:42:27
【问题描述】:

我有两列 Timestamp(2) START_DATE 和 END_DATE 类型的索引,以及一个带有 WHARE 子句的查询,例如:

WHERE C.START_DATE <= sysdate
  AND sysdate <= C.END_DATE

解释计划使 TABLE ACCESS FULL 而不是索引范围扫描。

-如果我将&lt;= 更改为=,则使用索引。

-如果我将sysdate 更改为systimestamp,在解释计划中会更糟:

SYS_EXTRACT_UTC(INTERNAL_FUNCTION(C.START_DATE))<=SYS_EXTRACT_UTC(SYSTIMESTAMP(6)) 

再次进行全面扫描。

-使用TO_TIMESTAMP 带来所需的索引范围扫描:

WHERE C.START_DATE <= TO_TIMESTAMP ('10-Sep-02 14:10:10.123000', 'DD-Mon-RR HH24:MI:SS.FF')
         AND TO_TIMESTAMP ('10-Sep-02 14:10:10.123000', 'DD-Mon-RR HH24:MI:SS.FF') <= C.END_DATE

但我需要使用当前日期。

有人能解释为什么会这样吗?

编辑: 这些是查询的简化版本,但会出现相同的行为。 解释计划。

EXPLAIN PLAN FOR
         select * 
           from communication c
            WHERE C.CAMPAIGN_START_DATE <= sysdate
         AND sysdate <= C.CAMPAIGN_END_DATE;

计划哈希值:4120205924

-------------------------------------------
| Id  | Operation         | Name          |
-------------------------------------------
|   0 | SELECT STATEMENT  |               |
|   1 |  TABLE ACCESS FULL| COMMUNICATION |
-------------------------------------------

.

EXPLAIN PLAN FOR
         select * 
           from communication c
            WHERE C.START_DATE = sysdate
         AND sysdate = C.END_DATE;

计划哈希值:1474125303

-------------------------------------------------------------------
| Id  | Operation                        | Name                   |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                        |
|   1 |  TABLE ACCESS BY INDEX ROWID     | COMMUNICATION          |
|   2 |   BITMAP CONVERSION TO ROWIDS    |                        |
|   3 |    BITMAP AND                    |                        |
|   4 |     BITMAP CONVERSION FROM ROWIDS|                        |
|   5 |      INDEX RANGE SCAN            | COMMUNICATION_START_DT |
|   6 |     BITMAP CONVERSION FROM ROWIDS|                        |
|   7 |      INDEX RANGE SCAN            | COMMUNICATION_END_TD   |
-------------------------------------------------------------------

【问题讨论】:

  • 请向我们展示完整的执行计划(编辑您的问题并将其添加为格式化文本)
  • @a_horse_with_no_name 我添加了解释计划。
  • 你删除了计划的一些重要部分:估计的行数
  • SYSDATEDATE 类型。与LOCALTIMESTAMPTIMESTAMP 值)一起使用会更好吗?
  • @WernfriedDomscheit 是的,这有效,数据库现在按索引扫描。谢谢。

标签: sql oracle


【解决方案1】:

您是否尝试过使用今天的时间戳? TO_TIMESTAMP ('27-oct-15 14:10:10.123000' ?使用两个不同的日期比较查询是没有意义的。

我的猜测是使用当前日期,&lt;= 意味着无论如何都要检查大部分行。这意味着使用索引不会带来太多好处

试试这个查询。

SELECT COUNT(*)

SELECT COUNT(*)
FROM ....
WHERE C.START_DATE <= sysdate
  AND sysdate <= C.END_DATE

如果两个COUNT(*) 非常相似,则意味着使用索引没有任何好处,因为无论如何都需要扫描整个表。

【讨论】:

  • count(*) 约为 150 000,where 子句约为 60 000
  • 您可以尝试使用(C.START_DATE, C.END_DATE) 的复合索引吗?您是否也尝试过使用今天作为日期的时间戳的示例?
  • 如果您要带回 1/3 的数据 EvGeni - 那么我不会感到惊讶的是它选择只进行全面扫描而不是扫描两个索引,合并结果以找到交集设置,然后最后去查找每个表。
  • @MichaelBroughton 这可能就是带有TO_TIMESTAMP ('10-Sep-02 的样本使用索引的原因。该查询可能返回更少的行。
  • @JuanCarlosOropeza 谢谢,这回答了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 2017-07-02
  • 1970-01-01
  • 1970-01-01
  • 2017-04-03
相关资源
最近更新 更多