这个问题现在已经不存在了
我重新计算了表格的统计数据,添加了新的索引,并重新分析了现有的索引。这完全改变了我的结果,并使下面大部分的发现无效。此时,我找到了一个足够高效且不需要任何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走快速通道?
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
的执行计划是什么?(这应该立即强制使用INDEX FULL SCAN
和COUNT STOPKEY
) - potashin