在Oracle XE 11g中使用不使用索引的两列排序

时间:2017-08-22 10:33:55

标签: sql indexing oracle11g oracle-xe

为什么这个简单的查询用于检索前100行,从给定时间开始,按时间和主键排序(client_time不唯一,这就是两者排序的原因),不使用索引?< / p>

SELECT *
FROM (SELECT *
      FROM requests
      WHERE client_time >= TO_TIMESTAMP('2017-07-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
      ORDER BY client_time ASC, transaction_id ASC
     )
WHERE rownum <= 100;

client_time为TIMESTAMP WITH LOCAL TIME ZONE,transaction_id为VARCHAR2(255 CHAR)

我期望它使用的索引被定义为

CREATE UNIQUE INDEX idx_time_id REQUESTS (client_time, transaction_id);

查询执行需要大约2秒钟(我的系统中有6百万行,生产中会更多)并且产生以下计划:

----------------------------------------------------------------------------------------------------
| Id  | Operation               | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                  |   100 |   110K|       | 31237   (1)| 00:06:15 |
|*  1 |  COUNT STOPKEY          |                  |       |       |       |            |          |
|   2 |   VIEW                  |                  |   860K|   931M|       | 31237   (1)| 00:06:15 |
|*  3 |    SORT ORDER BY STOPKEY|                  |   860K|    65M|    86M| 31237   (1)| 00:06:15 |
|*  4 |     TABLE ACCESS FULL   | REQUESTS         |   860K|    65M|       | 15294   (1)| 00:03:04 |
----------------------------------------------------------------------------------------------------

谓词信息(由操作ID标识):

   1 - filter(ROWNUM<=100)
   3 - filter(ROWNUM<=100)
   4 - filter("CLIENT_TIME">=TIMESTAMP' 2017-07-01 10:00:00,000000000')

当我删除ORDER BY子句的第二部分时,实际使用了该索引,并且查询在大约1ms内执行。

如果我的文章正确this Use the index, Luke,我的查询是否也不应该使用此索引?

UPDATE:

删除我的第二个订单栏后的计划如下:

--------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |   100 | 65100 |   106   (0)| 00:00:02 |
|*  1 |  COUNT STOPKEY                |                  |       |       |            |          |
|   2 |   VIEW                        |                  |   102 | 66402 |   106   (0)| 00:00:02 |
|   3 |    TABLE ACCESS BY INDEX ROWID| TRX_REQUESTS_LTZ |   102 |  8160 |   106   (0)| 00:00:02 |
|*  4 |     INDEX RANGE SCAN          | IDX_TIME_ID      |       |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

所以我认为WHERE子句不是问题所在。此外,重写WHERE之后没有任何改变:

WHERE client_time >= TO_TIMESTAMP_TZ('2017-07-01 10:00:00 +10:00', 'YYYY-MM-DD HH24:MI:SS TZH:TZM')

2 个答案:

答案 0 :(得分:0)

我怀疑原因是WHERE条款:

  WHERE client_time >= TO_TIMESTAMP('2017-07-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')

您已指定client_timeTIMESTAMP WITH TIMEZONE。但是,常量只是TIMESTAMP,没有时区。这意味着需要转换类型 - 这通常会阻碍索引的使用。

您应该尝试使用TO_TIMESTAMP_TZ(),记录here

答案 1 :(得分:0)

问题是我的索引是建立在VARCHAR2列上的。由于NLS,索引顺序不能像使用那样对结果集进行排序。

将transaction_id更改为NUMBER解决了问题。