在 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
这将需要进行两次范围扫描 before 和 after 你的 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%')
参见如何为查询生成执行计划
我创建了一个名为 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
这将需要进行两次范围扫描 before 和 after 你的 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%')
参见