这个问题现在没有实际意义
我重新计算了表格中的统计数据,添加了新的指数,并重新分析了现有指数.这完全改变了我的结果,并使我的大多数发现无效.在这一点上,我发现了一个新的查询,它具有足够的性能,不需要任何ROWNUM技巧.
此外,我认为值得指出的是,下面的查询,如所写,不能保证给出我想要的结果.将DISTINCT添加到中间查询可能会破坏我尝试在最里面的查询中应用的顺序.在实践中,这没有发生,但我不能依赖于此.
原始问题
我写了一个查询,当我输入一个假的ROWNUM检查时,它似乎表现得更好:
SELECT * FROM
(
SELECT DISTINCT * FROM
(
SELECT TransactionID FROM WOWDev.QueryLog WHERE UPPER(UserName)=UPPER('xyz') AND TransactionID IS NOT NULL ORDER BY TransactionID DESC
)
WHERE ROWNUM<=1e100 -- fake ROWNUM check! this gets us on the fast path
)
WHERE ROWNUM<=50
这是优化器计划.
SELECT STATEMENT, GOAL = ALL_ROWS 38025 50 650
COUNT STOPKEY
VIEW JSTILES 38025 801 10413
SORT UNIQUE NOSORT 38025 801 3204
COUNT STOPKEY
VIEW JSTILES 38024 801 3204
TABLE ACCESS BY INDEX ROWID WOWDEV QUERYLOG 38024 545694 9276798
INDEX FULL SCAN DESCENDING WOWDEV IX_QUERYLOG_TID 1263 212704
如果我注释掉了假的ROWNUM检查,那么查询突然崩溃并变得慢得多(以及成本为5倍).
SELECT STATEMENT, GOAL = ALL_ROWS 204497 50 650
COUNT STOPKEY
VIEW JSTILES 204497 34865 453245
SORT GROUP BY STOPKEY 204497 34865 592705
INDEX FAST FULL SCAN WOWDEV IX_QUERYLOG_USER_TID 204462 545694 9276798
显然,这也是一个完全不同的指数(一个显然不适合它).
如果我自然地简化查询并删除所有冗余,我们会得到一个与穷人版本类似的执行计划,同样性能也差.
SELECT * FROM
(
SELECT DISTINCT TransactionID
FROM WOWDev.QueryLog
WHERE UPPER(UserName) = UPPER('xyz')
AND TransactionID IS NOT NULL
ORDER BY TransactionID DESC
)
WHERE ROWNUM <= 50
解释如下:
SELECT STATEMENT, GOAL = ALL_ROWS 207527 50 650
COUNT STOPKEY
VIEW JSTILES 207527 34865 453245
SORT UNIQUE STOPKEY 207491 34865 592705
INDEX FAST FULL SCAN WOWDEV IX_QUERYLOG_USER_TID 204462 545694 9276798
如下所示,我尝试用ROWNUM> 0替换我的ROWNUM< = 1e100,这也达到了快速路径,但计划略有不同:
SELECT STATEMENT, GOAL = ALL_ROWS 38025 50 650
COUNT STOPKEY
VIEW JSTILES 38025 801 10413
SORT UNIQUE NOSORT 38025 801 3204
COUNT
FILTER
VIEW JSTILES 38024 801 3204
TABLE ACCESS BY INDEX ROWID WOWDEV QUERYLOG 38024 545694 9276798
INDEX FULL SCAN DESCENDING WOWDEV IX_QUERYLOG_TID 1263 212704
谁能解释这种行为?是否有更清洁,更少hacky的方式让Oracle走上快车道?