这个问题现在没有用了
我重新计算了表格中的统计数据,添加了新的指数,并重新分析了现有指数。这完全改变了我的结果,并使我的大多数发现无效。在这一点上,我发现了一个新的查询,它具有足够的性能,不需要任何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<=1e100
替换为ROWNUM>0
,这也是快速路径,但计划略有不同:
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走上快车道?
答案 0 :(得分:2)
这不一定是正确答案,但......
我过去曾使用过ROWNUM > 0
来强制实现&#39;数据。
这反过来允许查询处理器获得正确的基数。
例如,如果查询规划器认为特定谓词只返回一行,它通常会在其上使用笛卡尔连接。如果数据实际上不是一行而是很多,则笛卡尔连接会导致大量行和大量不正确的处理。添加ROWNUM > 0
会强制它评估每行的rownum,然后才能评估ROWNUM&gt; 0,有效地强制实现数据的实现
看起来这实际上并不是你的问题。
也许是因为数据的传播,它实现得更快,然后搜索表而不是首先检查索引。
在该计划转储中是否有办法解决谓词的应用位置?
遗憾的是,你必须UPPER
这个字段,因为它使它不具有可搜索性,并且不会在该字段上使用索引。
答案 1 :(得分:0)
我记得,在子查询中放置圆形谓词的一个影响是它可以防止谓词推送和某些类型的视图合并。
虽然它们通常都有利于查询性能,但在某些情况下它们会产生不良副作用。这曾经是一个可以用来代替优化器提示的技巧,以防止考虑转换。
答案 2 :(得分:-1)
您已经减少了添加&#34;假冒&#34; romwnum WHERE ROWNUM<=1e100
这指示数据库ROWNUM必须至多为1e100。
第一个查询更快的原因是外部选择需要处理一个小子集。
也许你可以更快地实现&#34;结果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<=50 -- move inside to get small result set
)