绑定变量导致 Oracle 中的完整 table 扫描

Bind variables results in full table scan in Oracle

检查具有 100 万条记录的 table 的查询成本会导致完全 table 扫描,而在 oracle 中使用实际值进行相同查询会导致成本显着降低。

这是 Oracle 的预期行为吗? 有没有办法告诉 Oracle 不要扫描完整的 table?

当使用绑定变量时,查询正在扫描完整 table:

查询成本随实际变量显着降低:

这是分页查询。您想要从 table 中检索少量记录,过滤它们在过滤集中的位置。您的投影包括 table 的所有列,因此您需要查询 table 以获取整行。问题是,为什么这两个查询变体有不同的计划?

让我们考虑第二个查询。您正在传递偏移量的硬值,因此优化器知道您需要排序集中的 11 个最近的行。该集合按索引列排序。最重要的元素是优化器知道您需要 11 行 。 11 是一百万的一个非常小的片段,因此使用索引读取来获取所需的行是一种有效的处理方式。该路径从索引的远端开始,读取最后 11 个条目并检索行。

现在,您的第一个查询具有开始和结束偏移量的绑定变量以及要returned 的行数。这很关键:优化器不知道您想要 return 十一行还是一万一千行。所以它选择了一个非常高的基数。原因是索引读取在检索大量行时性能非常差。完整 table 扫描是处理我们 table 大片的最佳方式。

Is this expected behaviour from Oracle ?

现在你明白了这一点,你就会发现这个问题的答案是。优化器根据我们提供的信息做出最佳决策。当我们提供硬值时,它会非常聪明。当我们提供模糊的数据时,它必须猜测;有时它的猜测不是我们预期的。

当预期结果集相似时,绑定变量对于运行具有不同值的相同查询非常有用。但是使用绑定变量来指定范围意味着结果集的大小可能会有很大的不同。

Is there a way to tell Oracle not to scan the full table ?

如果您可以修复页面大小,从而删除 :a2 参数,这将允许优化器生成更准确的计划。或者,如果您需要在一个小范围内(比如 10 - 100)改变页面大小,那么您可以尝试在查询中使用 /*+ cardinality (100) */ 提示;只要基数值在正确的数量级内,它就不必是精确值。

与所有性能问题一样,细节决定成败。因此,您需要对各种性能变化进行基准测试,并选择最适合您的特定用例的。