Oracle在加入时不使用索引

Loc*_*ock 8 oracle indexing performance join query-optimization

我很擅长索引和解释计划,所以请耐心等待!我正在尝试调整查询,但我遇到了问题.

我有两张桌子:

SKU
------
SKUIDX (Unique index)
CLRIDX (Index)
..
..

IMPCOST_CLR
-----------
ICCIDX (Unique index)
CLRIDX (Index)
...
..
Run Code Online (Sandbox Code Playgroud)

当我这样做时select * from SKU where clridx = 122,我可以看到它正在使用解释计划中的索引(它表示TABLE ACCESS .. INDEX,它表示OBJECT_NAME下的索引名称,选项是RANGE SCAN).

现在,当我尝试加入同一个字段时,它似乎没有使用索引(它表示TABLE ACCESS .. HASH JOIN和选项下,它表示FULL).

我应该寻找什么来试图看看为什么它没有使用索引?对不起,我不确定要输入什么命令来显示,所以如果您需要更多信息,请告诉我.

示例:
第一个查询:

  SELECT
    *
  FROM
    AP21.SKU
  WHERE
    CLRIDX = 100
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

第二个查询:

  SELECT
    *
  FROM
    AP21.IMPCOST_CLR
  WHERE
    CLRIDX = 100
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

第三个查询:

  SELECT
    *
  FROM
    AP21.SKU
  INNER JOIN
    AP21.IMPCOST_CLR ON
    IMPCOST_CLR.CLRIDX = SKU.CLRIDX
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

APC*_*APC 19

看看这个查询:

SELECT
    *
FROM
    AP21.SKU
INNER JOIN
    AP21.IMPCOST_CLR ON
    IMPCOST_CLR.CLRIDX = SKU.CLRIDX
Run Code Online (Sandbox Code Playgroud)

它没有额外的谓词.因此,您将SKU中的所有行连接到IMPCOST_CLR中的所有行.此外,您正在从两个表中选择所有列.

这意味着Oracle必须读取两个表的全部内容.最有效的方法是使用全表扫描,挖掘多块读取中的所有行,并使用散列来匹配连接的值.

基本上,它是一个set操作,这是SQL做得很好,而索引读取更多RBAR.现在,如果您更改了第三个查询以包含其他谓词,例如

WHERE SKU.CLRIDX = 100
Run Code Online (Sandbox Code Playgroud)

您很可能会看到访问路径恢复为INDEX RANGE SCAN.因为您只选择了少数几行,所以索引读取再次是更有效的路径.


"我试图调整的查询是数百个更长的时间,但要将其分解并逐步进行!"

这是一种很好的技术,但您需要了解Oracle Optimzer的工作原理.解释计划中有很多信息. 了解更多. 注意Rows每个步骤的列中的值.这告诉您Optimizer期望从操作中获得多少行.与第三个查询相比,前两个查询将看到非常不同的值.


Mar*_*and 6

现在,当我尝试加入同一个字段时,它似乎没有使用索引(它表示TABLE ACCESS .. HASH JOIN和选项下,它表示FULL).

这是因为HASH JOIN不对连接谓词使用(需要)索引:

http://use-the-index-luke.com/sql/join/hash-join-partial-objects