【问题标题】:Understanding Oracle Index Order了解 Oracle 索引顺序
【发布时间】:2015-09-08 10:00:36
【问题描述】:

我对此有点困惑,希望有人能提供帮助。我正在阅读 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)

但事情是这样的:在我自己的员工表 (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 indexing


    【解决方案1】:

    当您没有在谓词中指定索引的前导列时,Oracle 确实能够通过索引跳过扫描来使用复合索引。但是,这通常比常规索引扫描效率低得多。从概念上讲,您可以认为它对索引的前导列的每个不同值进行索引扫描。通常,如果前导列有几个不同的值并且尾随列特别有选择性,Oracle 只会考虑这种计划。我不希望这两者都是真的——大概ename 几乎是独一无二的,而job 的选择性相当低。我希望对表进行全面扫描会更有效率,所以我猜想你的统计数据有些“不可靠”。如果您的表特别小,那肯定会导致查询计划异常,因为每个计划似乎都非常便宜。

    在现实世界中,很少有人在查询计划中看到“索引跳过扫描”并认为“太好了!这就是我想要的计划”。这通常意味着出现了问题,但可能并没有像它可能出现的那么严重。

    【讨论】:

      【解决方案2】:

      好问题。

      显然,如果您的查询同时包含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 选择性列放在索引的前沿。 (另一个主要原因是压缩。)

      【讨论】:

      • 谢谢!我选择了你的答案而不是贾斯汀的答案,因为我发现你的答案好一点。但两者都传达了有用的信息。
      • 所以可以肯定的是,INDEX SKIP SCAN 并不意味着它实际上使用了索引,但它会尝试重建它以便它可以?
      • 不,没有重建正在进行。它使用索引。它只是转到索引中的一个点(使用上面的示例),前导列值为 1,然后对查询中谓词的第 2 列值进行范围扫描。然后索引中的点相同,这里的前导列值是 2,然后是 3,然后是 4。想法是,它将每个索引子集视为一个索引,并在索引周围“跳过”到整体的各个部分与当前查询相关的索引结构。没有进行任何形式的重建。希望这很清楚。
      【解决方案3】:

      大部分问题的答案:https://oracle-base.com/articles/9i/index-skip-scanning

      1) 这正是 INDEX SKIP SCAN 的用途。

      2) 是的,可以使用,但这取决于您的统计数据

      3) 它可能会也可能不会 -> 取决于您的统计数据

      4) 访问路径是关于选择要加载的数据块,过滤是关于如何过滤掉数据块中的行。

      5) DATE 索引的工作方式与其他数据类型的索引非常相似。 DATE 有 7 个字节长。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-12
        • 1970-01-01
        • 2011-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-25
        相关资源
        最近更新 更多