为什么这个简单的查询用于检索前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 |
----------------------------------------------------------------------------------------------------
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,我的查询是否也不应该使用此索引?
删除我的第二个订单栏后的计划如下:
--------------------------------------------------------------------------------------------------
| 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')
答案 0 :(得分:0)
我怀疑原因是WHERE
条款:
WHERE client_time >= TO_TIMESTAMP('2017-07-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
您已指定client_time
为TIMESTAMP WITH TIMEZONE
。但是,常量只是TIMESTAMP
,没有时区。这意味着需要转换类型 - 这通常会阻碍索引的使用。
您应该尝试使用TO_TIMESTAMP_TZ()
,记录here。
答案 1 :(得分:0)
问题是我的索引是建立在VARCHAR2
列上的。由于NLS,索引顺序不能像使用那样对结果集进行排序。
将transaction_id更改为NUMBER
解决了问题。