多列唯一约束中的列顺序有什么不同吗?有重复的索引是否合理?

bro*_*ng0 3 sql oracle indexing unique-constraint oracle11g

在史蒂夫·奥赫恩 (Steve O'Hearn) 的“SQL 认证专家考试指南”中,我找到了这一段:

在创建复合索引以及调用同一索引的多个约束时,在极少数情况下,需要特殊语法。例如,如果我们决定在 INVOICES 表中的两个列上创建一个复合索引,我们可以使用以下语法:

CREATE TABLE invoices
(
    invoice_id    NUMBER(11),
    invoice_date  DATE,
    CONSTRAINT    un_invoices_invoice_id UNIQUE (invoice_id, invoice_date)
                  USING INDEX (CREATE INDEX ix_invoices
                                      ON invoices(invoice_id, invoice_date)),
    CONSTRAINT    un_invoices_invoice_date UNIQUE (invoice_date, invoice_id)
                  USING INDEX ix_invoices
);
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

  1. 创建两个唯一约束仅更改声明中的列顺序有什么意义?

  2. 我们创建了一个多列索引:“invoice_id”作为第一列,“invoice_date”作为第二列。但是让我们假设我们真的经常运行与“invoice_date”本身相关的查询,而没有“invoice_id”的参与。在“invoice_date”上创建第二个单列索引是个好主意吗?我知道:

由于 Oracle 支持多列索引,因此很容易意外创建“重复”索引,这些索引会增加 DML 的开销并且无助于加快 SQL 执行速度[来源]

我也知道:

由于跳过扫描引用复合索引中任何列的 WHERE 子句,可能会在处理过程中调用索引。[史蒂夫·奥赫恩]

但我也知道:

这不如简单的单列索引那么有益,它的好处因第一列中值的唯一性而异。[史蒂夫·奥赫恩]

因此,假设我们很少在此表上使用 DML 命令,并且假设我们与 SELECT 的 WHERE 子句中的两列相关,就像分别与“index_date”或“index_id”相关。在某些情况下,创建两个索引是否合理?一,多列索引,在(index_id,index_date)上,第二,单列索引,在(index_date)?

Gor*_*off 5

你的问题是:

在某些情况下,创建两个索引是否合理?一,多列索引,在(index_id,index_date)上,第二,单列索引,在(index_date)上?

答案是“是”。第一个索引将用于满足以下条件的查询:

  • index_idwhere子句中过滤
  • 在子句上index_id和子句index_date中进行过滤where
  • index_id子句中的过滤where和排序依据index_date

在这些情况下不会使用第二个索引。它将用于:

  • index_datewhere子句中过滤

在这种情况下不会使用第一个索引。

索引中列的顺序很重要。它们是从左到右使用的。所以,这两个索引很有用。然而,单独使用第三个索引index_id是没有用的,因为第一个索引已经处理了使用该索引的相同情况。


APC*_*APC 5

你问

“创建两个唯一约束仅更改声明中的列顺序有什么意义?”

没有任何意义。复合约束中的列顺序没有任何区别:

SQL> select * from t23
  2  /

      COL1 COL
---------- ---
         1 WTF

SQL> create index t23_i on t23(col1, col2);

Index created.

SQL> alter table t23 add constraint t23_uk unique (col1 , col2) using index t23_i
  2  /

Table altered.

SQL> insert into t23 values (1, 'WTF')
  2  /
insert into t23 values (1, 'WTF')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated


SQL> alter table t23 drop  constraint t23_uk
  2  /

Table altered.

SQL> alter table t23 add constraint t23_uk unique (col2, col1) using index t23_i
  2  /

Table altered.

SQL> insert into t23 values (1, 'WTF')
  2  /
insert into t23 values (1, 'WTF')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated


SQL> 
Run Code Online (Sandbox Code Playgroud)

这就是考试填鸭式的问题:他们经常只说一些东西,而没有提供解释或上下文。

你还问:

“在 上创建第二个单列索引是个好主意invoice_date吗?”

在不知道数据的情况下很难判断,但我希望日期列的选择性低于 ID 列(尤其是在时间元素被截断的情况下),因此通常我希望索引能够以(invoice_date, invoice_id)任何方式构建。这可能允许我们使用索引压缩。

跳过扫描并不像史蒂夫所说的那样工作:它首先探测索引的前沿,但前提是复合索引中的第二列在 WHERE 子句中被引用。优化器可能会选择完全快速索引扫描来搜索第三列或更低的列。如果前沿有太多不同的值,它也不会选择跳过扫描路径:另一个有选择地以低列领先的好理由。

所以,这并不能完全回答你的问题,但我认为它确实传达了一个重要的观点:没有通用的规则来管理为性能创建索引。我们需要了解数据的概况——它的值分布和数量——以及将使用该表的最重要的查询。