Гро*_*ный 8 sql oracle indexing optimization plsql
我有一个简单的查询,它选择由其他索引列筛选的列之一排序的前200行.令人困惑的是为什么PL/SQL Developer中的查询计划显示只有在我选择所有行时才使用此索引,例如:
SELECT * FROM
(
SELECT *
FROM cr_proposalsearch ps
WHERE UPPER(ps.customerpostcode) like 'MK3%'
ORDER BY ps.ProposalNumber DESC
)
WHERE ROWNUM <= 200
Run Code Online (Sandbox Code Playgroud)
计划显示它使用索引CR_PROPOSALSEARCH_I1,它是两列的索引:PROPOSALNUMBER&UPPER(CUSTOMERNAME),执行时需要0.985秒:

如果我摆脱ROWNUM条件,该计划是我所期望的,并在0.343秒内执行:

哪里 index XIF25CR_PROPOSALSEARCH is on CR_PROPOSALSEARCH (UPPER(CUSTOMERPOSTCODE));
怎么会?
编辑:我收集了关于cr_proposalsearch表的统计信息,现在两个查询计划都显示它们使用XIF25CR_PROPOSALSEARCH索引.
包括ROWNUM会更改优化程序关于哪个是更有效路径的计算.
当您执行这样的前n个查询时,并不一定意味着Oracle将获取所有行,对它们进行完全排序,然后返回最高行.COUNT STOPKEY执行计划中的操作表明Oracle只会在找到您要求的行数之前执行基础操作.
优化器已计算出完整查询将获取并排序77K行.如果它将此计划用于top-n查询,则必须执行大量的那些行才能找到前200个(它不一定要对它们进行完全排序,因为它不关心确切的顺序超过顶部的行;但它必须查看所有这些行).
top-n查询的计划使用另一个索引来避免必须排序.它按顺序考虑每一行,检查它是否与谓词匹配,如果是,则返回它.当它返回200行时,就完成了.它的计算表明,这对于获得少量行更有效.(当然,这可能不对;你还没有说过这些查询的相对表现是什么.)
如果优化器在请求所有行时选择此计划,则必须按降序读取整个索引,从ROWID获取表中的每一行,以检查谓词.这将导致大量额外的I/O并检查许多不会返回的行.所以在这种情况下,它决定使用索引customerpostcode更有效.
如果逐渐增加从top-n查询返回的行数,您可能会发现计划从第一个切换到第二个的临界点.仅仅从两个计划的成本来看,我猜这可能是大约1,200行.