在 Oracle 中的 SELECT 语句中使用索引

Use an index in a SELECT statement in Oracle

我创建了一个名为 Z7 的索引,我想在 SELECT 语句中使用它,如下所示:

SELECT * FROM Employees WITH (INDEX(Z7)) WHERE First_Name NOT LIKE ('J%');

但它向我显示了这个错误:

ORA-00933: SQL command not properly ended

与可以通过 索引范围扫描 解析的 LIKE 谓词相反,Oracle 中没有索引访问路径可以实现 NOT LIKE这将需要进行两次范围扫描 beforeafter 你的 LIKE 值。

让我们在这个设置中用一个 table 来说明它,它只有一行满足你的 not like 谓词。

create table Employees as
select 'J'||rownum as First_Name, lpad('x',1000,'y') pad from dual connect by level <= 10000
union all 
select 'Xname', 'zzzzz' from dual;

create index Z7 on Employees (First_Name);

查询

SELECT * FROM Employees  WHERE First_Name NOT LIKE ('J%');

按预期执行 FULL TABLE SCAN

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |    37 | 37259 |   398   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |    37 | 37259 |   398   (1)| 00:00:01 |
-------------------------------------------------------------------------------

 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("FIRST_NAME" NOT LIKE 'J%')

你可能hint Oracle使用索引如下(注意你的语法FROM Employees WITH (INDEX(Z7)) WHERE是错误的,导致你的错误!)

SELECT /*+ index(Employees Z7) */ * FROM Employees  WHERE First_Name NOT LIKE ('J%');

这确实会导致索引使用,但不是您可能想要的那样。

如果您检查执行计划,您会看到 INDEX FULL SCAN,这意味着 Oracle 从 A 遍历 完整索引 Z,过滤索引中 not like 您的谓词的全部内容(请参阅下面计划中的 FILTER),并为选定的键访问 table.

因此,通常您不会对 大型索引 的计划感到满意,因为它比完整 table 扫描花费的时间要长得多。

-------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |           |  9433 |  9276K|  2912   (1)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |  9433 |  9276K|  2912   (1)| 00:00:01 |
|*  2 |   INDEX FULL SCAN                   | Z7        |  9433 |       |    25   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("FIRST_NAME" NOT LIKE 'J%') 

参见如何为查询生成执行计划