了解 Oracle 索引顺序
Understanding Oracle Index Order
我对此有点困惑,希望有人能提供帮助。我正在阅读马库斯·温南德 (Markus Winand) 的优秀 Use The Index Luke
书,其中有关于连接索引的内容。
创建了一个 (EMPLOYEE_ID, SUBSIDIARY_ID)
索引,所以当他查询
SELECT first_name, last_name
FROM employees
WHERE subsidiary_id = 20
这个执行计划出现了:
----------------------------------------------------
| Id | Operation | Name | Rows | Cost |
----------------------------------------------------
| 0 | SELECT STATEMENT | | 106 | 478 |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 106 | 478 |
----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SUBSIDIARY_ID"=20)
但事情是这样的:我自己的员工 table (empno, ename, init, job, mgr, bdate, msal, comm, deptno)
我在 (ENAME, JOB)
上创建了一个连接索引
查询 select ename from employees where job = 'TRAINER';
给出了以下执行计划:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4271702361
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 45 | 1 (0)| 00:00:01 |
|* 1 | INDEX SKIP SCAN | ENAME_INDEX | 3 | 45 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - access("JOB"='TRAINER')
filter("JOB"='TRAINER')
所以现在我有点困惑。
1) 为什么尽管有命令,我的索引仍然被使用?
2) 索引跳过扫描是否适用于我不在 where 子句中使用第一列的任何连接索引?
3) 索引跳过扫描对性能有重大影响吗?
4) 怎么会有访问谓词和过滤谓词?
虽然我在这里,但我还有一个问题
5) 我需要在索引日期上采取任何预防措施吗?
当您没有在谓词中指定索引的前导列时,Oracle 确实能够通过索引跳过扫描使用复合索引。但是,这通常比常规索引扫描效率低得多。从概念上讲,您可以认为它对索引前导列的每个不同值进行索引扫描。通常,如果前导列有几个不同的值并且尾随列特别有选择性,Oracle 只会考虑这种计划。我不希望这两者都成立——大概 ename
几乎是唯一的,而 job
的选择性较低。我希望对 table 进行全面扫描会更有效率,所以我猜想您的统计数据是 "wonky"。如果您的 table 特别小,那肯定会导致查询计划不寻常,因为每个计划似乎都非常便宜。
在现实世界中,极少数情况下有人在查询计划中看到 "index skip scan" 并认为 "Great! That's the plan I wanted." 这通常意味着出现了问题,但它可能并没有消失尽可能错误。
好问题。
显然,如果您的查询同时包含 ENAME
和 JOB
,那么 Oracle 会使用索引,或者使用 INDEX RANGE SCAN
或 INDEX UNIQUE SCAN
。但是,查询谓词中未提供索引的前沿 ENAME
。因此,Oracle 的基于成本的优化器 (CBO) 有一个选择。它可以选择执行 FULL TABLE SCAN
(忽略索引)或 INDEX SKIP SCAN
.
我假设您知道 FULL TABLE SCAN
是什么,所以我不会深入探讨。
那么,什么是 INDEX SKIP SCAN
?嗯,根据索引的形状和大小,CBO 可以选择进行跳过扫描。当索引中的前导列的不同值数量相对较少时,通常会发生这种情况。实际情况是,Oracle 获取索引并将其有效地分解为多个索引。假设前导列有 4 个不同的值 (1-4)。因此,Oracle 查看前导列等于 1 的索引子集,并对索引的该子集进行范围扫描,然后对前导列等于 2、3、4 的索引子集执行相同的操作。在某些情况下,根据前导列有多少不同值,以及第二列范围扫描的选择性,此访问路径可能比 FULL TABLE SCAN
.
成本更低
这是另一个原因,如果所有其他条件都相同,您可能希望将 less 选择性列放在索引的前沿。 (另一个主要原因是压缩。)
大部分问题的答案:https://oracle-base.com/articles/9i/index-skip-scanning
1) 这正是 INDEX SKIP SCAN 的用途。
2)是的,可以用,但是要看你的统计
3) 可能会也可能不会 -> 取决于您的统计数据
4) 访问路径是关于选择要加载的数据块,过滤是关于如何从数据块中过滤掉行。
5) DATE 上的索引与其他数据类型上的索引非常相似。 DATE 的长度为 7 个字节。
我对此有点困惑,希望有人能提供帮助。我正在阅读马库斯·温南德 (Markus Winand) 的优秀 Use The Index Luke
书,其中有关于连接索引的内容。
创建了一个 (EMPLOYEE_ID, SUBSIDIARY_ID)
索引,所以当他查询
SELECT first_name, last_name
FROM employees
WHERE subsidiary_id = 20
这个执行计划出现了:
----------------------------------------------------
| Id | Operation | Name | Rows | Cost |
----------------------------------------------------
| 0 | SELECT STATEMENT | | 106 | 478 |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 106 | 478 |
----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SUBSIDIARY_ID"=20)
但事情是这样的:我自己的员工 table (empno, ename, init, job, mgr, bdate, msal, comm, deptno)
我在 (ENAME, JOB)
查询 select ename from employees where job = 'TRAINER';
给出了以下执行计划:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4271702361
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 45 | 1 (0)| 00:00:01 |
|* 1 | INDEX SKIP SCAN | ENAME_INDEX | 3 | 45 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
1 - access("JOB"='TRAINER')
filter("JOB"='TRAINER')
所以现在我有点困惑。
1) 为什么尽管有命令,我的索引仍然被使用?
2) 索引跳过扫描是否适用于我不在 where 子句中使用第一列的任何连接索引?
3) 索引跳过扫描对性能有重大影响吗?
4) 怎么会有访问谓词和过滤谓词?
虽然我在这里,但我还有一个问题
5) 我需要在索引日期上采取任何预防措施吗?
当您没有在谓词中指定索引的前导列时,Oracle 确实能够通过索引跳过扫描使用复合索引。但是,这通常比常规索引扫描效率低得多。从概念上讲,您可以认为它对索引前导列的每个不同值进行索引扫描。通常,如果前导列有几个不同的值并且尾随列特别有选择性,Oracle 只会考虑这种计划。我不希望这两者都成立——大概 ename
几乎是唯一的,而 job
的选择性较低。我希望对 table 进行全面扫描会更有效率,所以我猜想您的统计数据是 "wonky"。如果您的 table 特别小,那肯定会导致查询计划不寻常,因为每个计划似乎都非常便宜。
在现实世界中,极少数情况下有人在查询计划中看到 "index skip scan" 并认为 "Great! That's the plan I wanted." 这通常意味着出现了问题,但它可能并没有消失尽可能错误。
好问题。
显然,如果您的查询同时包含 ENAME
和 JOB
,那么 Oracle 会使用索引,或者使用 INDEX RANGE SCAN
或 INDEX UNIQUE SCAN
。但是,查询谓词中未提供索引的前沿 ENAME
。因此,Oracle 的基于成本的优化器 (CBO) 有一个选择。它可以选择执行 FULL TABLE SCAN
(忽略索引)或 INDEX SKIP SCAN
.
我假设您知道 FULL TABLE SCAN
是什么,所以我不会深入探讨。
那么,什么是 INDEX SKIP SCAN
?嗯,根据索引的形状和大小,CBO 可以选择进行跳过扫描。当索引中的前导列的不同值数量相对较少时,通常会发生这种情况。实际情况是,Oracle 获取索引并将其有效地分解为多个索引。假设前导列有 4 个不同的值 (1-4)。因此,Oracle 查看前导列等于 1 的索引子集,并对索引的该子集进行范围扫描,然后对前导列等于 2、3、4 的索引子集执行相同的操作。在某些情况下,根据前导列有多少不同值,以及第二列范围扫描的选择性,此访问路径可能比 FULL TABLE SCAN
.
这是另一个原因,如果所有其他条件都相同,您可能希望将 less 选择性列放在索引的前沿。 (另一个主要原因是压缩。)
大部分问题的答案:https://oracle-base.com/articles/9i/index-skip-scanning
1) 这正是 INDEX SKIP SCAN 的用途。
2)是的,可以用,但是要看你的统计
3) 可能会也可能不会 -> 取决于您的统计数据
4) 访问路径是关于选择要加载的数据块,过滤是关于如何从数据块中过滤掉行。
5) DATE 上的索引与其他数据类型上的索引非常相似。 DATE 的长度为 7 个字节。