Oracle查询在索引编号列上使用'like',性能不佳

Jam*_*ins 9 sql oracle indexing oracle10g sql-like

在查询1上,即使id是索引列,也正在执行全表扫描.查询2实现了相同的结果,但速度更快.如果运行查询1返回索引列,则它会快速返回,但如果返回非索引列或整行,则查询需要更长时间.

在查询3中,它运行得很快但是"代码"列是VARCHAR2(10)而不是NUMBER(12),并且索引方式与"id"相同.

为什么查询1没有意识到它应该使用索引?是否应该更改某些内容以允许索引编号列更快地执行?

[查询1]

select a1.*
from people a1
where a1.id like '119%' 
and rownum < 5
Run Code Online (Sandbox Code Playgroud)

解释计划
SELECT STATEMENT ALL_ROWS
成本:67字节:2,592基数:4
2 COUNT STOPKEY
    1表访问全表人员
     费用:67字节:3,240基数:5

[查询2]

select a1.*
from people a1, people a2
where a1.id = a2.id
and a2.id like '119%' 
and rownum < 5
Run Code Online (Sandbox Code Playgroud)

解释计划
SELECT STATEMENT ALL_ROWS
成本:11字节:2,620基数:4
5 COUNT STOPKEY
    4表格访问按行ROWID表人员
    成本:3字节:648基数:1
        3 NESTED LOOPS
        成本:11字节:2,620基数:4
            1 INDEX FULL FULL SCAN INDEX people_IDX3
            成本:2字节:54,796基数:7,828
            2 INDEX RANGE SCAN INDEX people_IDX3
            成本:2基数:1

[查询3]

select a1.*
from people a1
where a1.code like '119%' 
and rownum < 5
Run Code Online (Sandbox Code Playgroud)

说明计划
SELECT STATEMENT ALL_ROWS
成本:6字节:1,296基数:2
   3 COUNT STOPKEY
      2表按STEX ROWID表访问人员
      费用:6字节:1,296基数:2
         1 INDEX RANGE SCAN INDEX people_IDX4
         成本:3基数:2

Ser*_*nik 14

LIKE模式匹配条件期望将字符类型视为左侧和右侧操作数.当遇到NUMBER时,它会隐式将其转换为char.您的查询1基本上是默默地重写为:

SELECT a1.*
  FROM people a1
 WHERE TO_CHAR(a1.id) LIKE '119%'
   AND ROWNUM < 5
Run Code Online (Sandbox Code Playgroud)

在你的情况下会发生这种情况,这有两个原因:

  1. 每行都执行转换,这很慢;
  2. 由于WHERE谓词中的函数(虽然是隐式),Oracle无法在A1.ID列上使用索引.

要绕过它,您需要执行以下操作之一:

  1. 在列上创建基于函数的索引A1.ID:

    CREATE INDEX people_idx5 ON people (TO_CHAR(id));

  2. 如果需要匹配ID列的前3个字符的记录,请创建另一个包含这3个字符的NUMBER类型的列,并在其上使用plain =运算符.

  3. 创建一个单独ID_CHAR的类型列VARCHAR2并填充它TO_CHAR(id).将其编入索引并使用而不是ID在您的WHERE条件下.

    当然,如果您选择基于现有ID列创建其他列,则需要保持这两个列同步.您可以批量执行此操作作为单个UPDATE,或在ON-UPDATE触发器中,或将该列添加到适当的代码中的INSERT和UPDATE语句.