43

有人可以澄清没有唯一约束(Oracle)的唯一索引的目的是什么?例如,

create table test22(id int, id1 int, tmp varchar(20));
create unique index idx_test22 on test22(id);
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // ok
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // fails, ORA-00001: unique   
  // constraint (TEST.IDX_TEST22) violated

到目前为止,看起来有一个约束。但

create table test33(id int not null primary key, 
test22_id int not null, 
foreign key(test22_id) references test22(id) );

也失败了"ORA-02270: no matching unique or primary key for this column-list"。我完全被这种行为弄糊涂了。有没有约束?

有很多文章解释了为什么可以有一个没有唯一索引的唯一约束;这很清楚,而且很有意义。但是,我不明白没有约束的唯一索引的原因。

4

4 回答 4

58

约束和索引是独立的逻辑实体。例如,唯一约束在USER_CONSTRAINTS(或ALL_CONSTRAINTSDBA_CONSTRAINTS)中可见。USER_INDEXES索引在(或ALL_INDEXESDBA_INDEXES)中可见。

唯一约束由索引强制执行,尽管可以(有时是必要的)使用非唯一索引强制执行唯一约束。例如,可延迟的唯一约束是使用非唯一索引强制执行的。如果您在列上创建非唯一索引并随后创建唯一约束,则还可以使用该非唯一索引来强制执行唯一约束。

在实践中,唯一索引的行为非常类似于唯一的、不可延迟的约束,因为它引发的错误与唯一约束引发的错误相同,因为唯一约束的实现使用了索引。但它并不完全相同,因为没有约束。因此,正如您所见,没有唯一约束,因此您无法创建引用该列的外键约束。

在某些情况下,您可以创建无法创建唯一约束的唯一索引。例如,强制条件唯一性的基于函数的索引。如果我想创建一个支持逻辑删除但确保COL1所有未删除行都是唯一 的表

SQL> ed
Wrote file afiedt.buf

  1  CREATE TABLE t (
  2    col1 number,
  3    deleted_flag varchar2(1) check( deleted_flag in ('Y','N') )
  4* )
SQL> /

Table created.

SQL> create unique index idx_non_deleted
  2      on t( case when deleted_flag = 'N' then col1 else null end);

Index created.

SQL> insert into t values( 1, 'N' );

1 row created.

SQL> insert into t values( 1, 'N' );
insert into t values( 1, 'N' )
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.IDX_NON_DELETED) violated


SQL> insert into t values( 1, 'Y' );

1 row created.

SQL> insert into t values( 1, 'Y' );

1 row created.

但是,如果我们谈论的是直接唯一的非基于函数的索引,那么创建索引而不是创建约束确实更有意义的情况可能相对较少。另一方面,它在实践中产生很大差异的情况相对较少。您几乎从不想声明引用唯一约束而不是主键约束的外键约束,因此您很少会因为只创建索引而不创建约束而丢失某些东西。

于 2011-09-22T22:01:03.840 回答
3

正如其他答案中已经解释的那样:约束和索引是不同的实体。但他们缺乏关于该主题的准确定义和官方评论。在我们讨论这两个实体之间的关系之前,让我们看看它们彼此独立的目的。

约束1的目的:

使用约束来定义完整性约束——限制数据库中值的规则。

索引2的目的:

您可以在列上创建索引以加快查询速度。索引为返回一小部分表行的操作提供更快的数据访问。

一般来说,在以下任何一种情况下,您都应该在列上创建索引:

  • 该列被频繁查询。
  • 列上存在参照完整性约束。
  • 列上存在唯一键完整性约束。

现在我们知道了什么是约束和索引,但是它们之间的关系是什么?

索引和约束之间的关系是3

  • 约束可能会创建索引或使用现有索引来有效地执行自身。例如,PRIMARY KEY 约束将创建一个索引(取决于唯一或非唯一),或者它将找到现有的合适索引并使用它。

  • 索引与约束无关。索引是索引。

因此,约束可能会创建/使用和索引。一个 INDEX 就是一个 INDEX,仅此而已,仅此而已。

因此,总结一下并直接从您的问题中解决以下句子:

但是,我不明白没有约束的唯一索引的原因。

索引加速查询和完整性检查(约束)。同样对于条件唯一性,使用唯一(功能)索引,因为这无法通过约束来实现。

希望这能为整个主题带来更多的澄清,但原始问题的一个方面仍未得到解答:

为什么不存在约束时会出现以下错误:

ORA-00001: 违反了唯一约束 (TEST.IDX_TEST22)

答案很简单:没有约束并且错误消息将其命名错误!

请参阅官方“Oracle Ask TOM”评论4对同一问题:

这不是一个约束。错误消息“命名错误”。
如果它是一个约束,你可以为它创建一个外键——但你不能。

希望能帮助到你。

链接:

1 关于约束的 Oracle 10g 文档

2 关于选择索引策略的 Oracle 10g 文档

3 4 "Oracle Ask TOM" 对类似问题的回答

于 2020-01-20T10:51:26.277 回答
2

在这种情况下可能有用的另一点是:禁用/删除现有的唯一约束不会删除基础唯一索引。您必须明确删除唯一索引。

于 2015-10-08T07:23:37.800 回答
1

您不能通过声明唯一约束来实现条件唯一性,但可以通过声明唯一索引来实现。

如果您尝试执行以下操作,请支持:

alter table test22 
add constraint test22_u 
unique (id, case when tmp = 'aaa' then null else tmp end);

ORA-00904: : invalid identifier 

但是如果你可以通过使用唯一索引来做到这一点

create unique index test22_u 
on test22 ( customer_id, 
case when is_default = 'Y' then null else address_id end)
于 2018-10-28T13:24:52.610 回答