我正在尝试在一个记录超过100万的表中超过100K行的用户按时间检索最后20行。当用户具有少量记录时,查询性能很好(以ms为单位)。但是,对于拥有大约10K-100K记录的用户,需要2分钟以上才能获取20条记录。
以下是查询:
select * from ( select * from TABLE1
where USER_ID= 41063660 and
COL1=0 and COL2 = 0
order by LAST_EVENT_DATE desc) where rownum <= 20 ;
有一个索引(I_LASTEVENTDT)(USER_ID,COL1,COL2,LAST_EVENT_DATE DESC)
以下是解释计划:
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 38960 | | 66959 (1)| 00:13:24 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | VIEW | | 65500 | 121M| | 66959 (1)| 00:13:24 |
|* 3 | SORT ORDER BY STOPKEY | | 65500 | 96M| 102M| 66959 (1)| 00:13:24 |
| 4 | TABLE ACCESS BY INDEX ROWID| TABLE1 | 65500 | 96M| | 47280 (1)| 00:09:28 |
|* 5 | INDEX RANGE SCAN | I_LASTEVENTDT | 65500 | | | 309 (0)| 00:00:04 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=20)
3 - filter(ROWNUM<=20)
5 - access("USER_ID"=41063660 AND "COL1"=0 AND
"COL2"=0)
我试图按照http://use-the-index-luke.com/sql/sorting-grouping/indexed-order-by
上给出的示例进行操作我也试过在(USER_ID,COL1,COL2)和(LAST_EVENT_DT DESC)上创建一个单独的索引,并尝试索引(USER_ID,LAST_EVENT_DT DESC)。即使对于后一个索引,它的性能也更糟糕,它摆脱了排序顺序。
如何从此查询中获得更好的效果?
提前致谢。
答案 0 :(得分:0)
首先尝试类似:
SELECT *
FROM
(SELECT *, ROW_NUMBER() OVER (ORDER BY last_event_date desc) R
FROM table1
WHERE user_id = 41063660
AND col1 = 0
AND col2 = 0)
WHERE R <= 20;
如果证明不快,请尝试:
SELECT *
FROM table1,
( SELECT last_event_date, ROW_NUMBER() OVER (ORDER BY last_event_date desc) R
FROM table1
WHERE user_id = 41063660
AND col1 = 0
AND col2 = 0 ) sub
WHERE table1.user_id = 41063660
AND table1.col1 = 0
AND table1.col2 = 0
AND sub.R = 20
AND table1.last_event_date >= sub.last_event_date
AND ROWNUM <= 20;
可能有一种更直接的方式来编写它 - 我没有可以使用的Oracle实例来试用它。
另一种方法是实现一个SQL函数,只是为了在给定某些键的情况下获取第20行(或第N行)的日期。然后以类似于我的第二个示例但没有子查询的方式调用该SQL函数。
答案 1 :(得分:0)
我认为你应该寻找一个Index Fast Full Scan并且不要整行排序。此外,我正在努力获得一小部分记录(20),并将它们再次加入主表。
with Dates as (
select /*+ Materialize */ LAST_EVENT_DATE
from ( select LAST_EVENT_DATE
from TABLE1
where USER_ID= 41063660
and COL1=0
and COL2 = 0
order by LAST_EVENT_DATE desc)
where rownum <= 20 )
select t2.*
from (
select t1.*
from TABLE1 t1 join Dates on t1.LAST_EVENT_DATE >= Dates.LAST_EVENT_DATE
and t1.USER_ID= 41063660
and t1.COL1=0
and t1.COL2 = 0
order by t1.LAST_EVENT_DATE desc) as t2
where rownum <= 20;