了解 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." 这通常意味着出现了问题,但它可能并没有消失尽可能错误。

好问题。

显然,如果您的查询同时包含 ENAMEJOB,那么 Oracle 会使用索引,或者使用 INDEX RANGE SCANINDEX 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 个字节。