将时间戳与< =或> =进行比较时,不使用Oracle Index

时间:2015-10-27 16:06:30

标签: sql oracle

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

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

解释计划使TABLE ACCESS FULL而不是Index range scan。

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

- 如果我将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   |
-------------------------------------------------------------------

1 个答案:

答案 0 :(得分:3)

你今天在时间戳上试了吗? TO_TIMESTAMP ('27-oct-15 14:10:10.123000'?使用两天不同来比较查询是没有意义的。

我的猜测是使用当前日期,而<=将意味着检查大多数行。这意味着使用索引不会带来太多好处

尝试此查询。

SELECT COUNT(*)

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

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