约束和索引的关系

教程发布:风哥 教程分类:ITPUX技术网 更新日期:2022-02-12 浏览学习:304

很多人比较纠结的约束和索引的关系
zz: jeanron100

最近有不少朋友留言或者微信问我一个问题,出乎我的意料,问

题竟然都是很相似的,所以我统一答复一下。
之前写了一篇文章 一个清理和查询都要兼顾的简单方案,看来

很多朋友还是很关心这个分区索引中的唯一性约束是怎么建立的

。我举个例子,当然内容中会贯穿说到你们的疑问,而且很可能

你么对于约束和索引还是存在这一些误解。
首先我们创建一个测试表,为了简单起见,也没有注意很多的命

名规则了。
create table test (id number,name varchar2(30))
partition by range(id)
(
partition p1 values less than(1),
partition p100 values less than (100),
partition p200 values less than(200)
);
我们就举unique约束的例子吧。
添加约束有很多种语法来实现。比如下面的三种
alter table test modify(id unique);
alter table test add constraint con_test_id_uq

unique(id);
alter table test add (constraint con_test_id_uq

unique(id));
首先我们来简单说明一个地方,就是generated的含义。
创建一个唯一性约束
alter table test modify(id unique);
这个时候查看约束的时候,发现约束名是系统自动生成的。
SQL> select constraint_name,table_name from

user_constraints where table_name='TEST';
CONSTRAINT_NAME TABLE_NAME
------------------------------ ----------------------

--------
SYS_C0031909 TEST
那么对应的index的情况如何呢。发现也是自动生成的,这个时

候字段generated的含义就是约束名是系统自动生成的。
SELECT

OWNER,CONSTRAINT_NAME,TABLE_NAME,GENERATED,INDEX_NAME

FROM USER_CONSTRAINTS WHERE TABLE_NAME='TEST';
OWNER CONSTRAINT_NAME

TABLE_NAME GENERATED

INDEX_NAME
------------------------------ ----------------------

-------- ------------------------------ -------------

------- ------------------------------
TEST SYS_C0031909

TEST GENERATED NAME

SYS_C0031909
好了,我们删除这个约束,继续测试,删除的同时会把约束也一

并删除。
SQL> ALTER TABLE TEST DROP CONSTRAINT SYS_C0031909

CASCADE;
Table altered.
这个时候我们创建一个约束,指定约束名。当然下面两种语法都

没有问题的。这就体现了Oracle语法解析器的强大之处。
alter table test add constraint con_test_id_uq

unique(id);
--alter table test add (constraint con_test_id_uq

unique(id));
当然创建出来约束之后,再来看看约束udev情况。
SQL> select constraint_name,table_name from

user_constraints where table_name='TEST';
CONSTRAINT_NAME TABLE_NAME
------------------------------ ----------------------

--------
CON_TEST_ID_UQ TEST
查看索引的情况,发现这个时候generated是user name,也就是

用户指定的名字。
SQL> SELECT

OWNER,CONSTRAINT_NAME,TABLE_NAME,GENERATED,INDEX_NAME

FROM USER_CONSTRAINTS WHERE TABLE_NAME='TEST';

OWNER CONSTRAINT_NAME

TABLE_NAME GENERATED

INDEX_NAME
------------------------------ ----------------------

-------- ------------------------------ -------------

------- ------------------------------
TEST CON_TEST_ID_UQ

TEST USER NAME

CON_TEST_ID_UQ
好了,到了大家关注的地方了,这个时候对这个分区表创建唯一

性约束,默认是会创建一个唯一性索引,但是这个索引是一个全

局索引。查看分区索引的数据字典视图,没有任何信息可以佐证


SQL> SELECT INDEX_NAME,PARTITION_NAME FROM

USER_IND_PARTITIONS WHERE INDEX_NAME='CON_TEST_ID_UQ';
no rows selected

好了,这个时候我来矫正一些知识点,首先来说上面两种创建约

束的方式,从规范的角度来说应该是需要使用第二种的,约束名

也是望名知义。小规则还是包含着大智慧。
然后对于创建Unique的本地约束,带有本地索引该怎么做呢,这

个时候需要先创建索引,然后创建约束绑定起来。
首先删除创建的测试约束,开始正式的创建。alter table

test drop constraint con_test_id_uq;
创建本地索引。
create unique index ind_test_uq on test(id) local;
这个时候还没有唯一性约束生成。
SQL> SELECT

OWNER,CONSTRAINT_NAME,TABLE_NAME,GENERATED,INDEX_NAME

FROM USER_CONSTRAINTS WHERE TABLE_NAME='TEST';
no rows selected
然后创建约束,这个时候仔细观察,其实会发现约束名和索引名

是不同的。也是各司其职。
alter table test add constraint con_test_uq unique(id)

using index ind_test_uq ;
SQL> SELECT

OWNER,CONSTRAINT_NAME,TABLE_NAME,GENERATED,INDEX_NAME

FROM USER_CONSTRAINTS WHERE TABLE_NAME='TEST';
OWNER CONSTRAINT_NAME

TABLE_NAME GENERATED

INDEX_NAME
-------------------- ------------------------------ -

----------------------------- -------------- --------

----------------------
TEST CON_TEST_UQ

TEST USER NAME

IND_TEST_UQ
这个时候索引约束就映射起来了。如果直接删除索引,会有下面

的报错。
SQL> DROP INDEX IND_TEST_UQ;
DROP INDEX IND_TEST_UQ
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of

unique/primary key
对于这类的错误,尤其是生产环境中还是让人非常头痛的。
我们可以drop或者disable约束,然后删除即可。
SQL> ALTER TABLE TEST DROP CONSTRAINT CON_TEST_UQ;
Table altered.

SQL> DROP INDEX IND_TEST_UQ;
Index dropped.
如果你觉得这种方式有些特别,那么我们来看看tom怎么说。在

这一点上,其实Oracle也是建议做一个权衡,还是做到索引和约

束的分离。
Oracle recommends that unique indexes be created

explicitly, and not through enabling a unique

constraint on a table.
Alternatively, you can define UNIQUE integrity

constraints on the desired columns. Oracle enforces

UNIQUE integrity constraints by automatically defining

a unique index on the unique key. However, it is

advisable that any index that exists for query

performance, including unique indexes, be created

explicitly.

当然如果觉得上面的描述有些长,来两句简单的。
A unique constraint does not necessarily create an

index.
A unique constraint does not necessarily create a

UNIQUE index.

如果还觉得不好理解,还有方法。
a) unique did not create an index
b) unique does not need a unique index
如果还不理解,我们做个小的实验。
SQL> create table t( x int, y int );
Table created.

SQL> create index t_idx on t(x,y);
Index created.

SQL> alter table t add constraint t_unique unique(x);
Table altered.

SQL> select index_name,uniqueness,index_type from

user_indexes where table_name ='T';
INDEX_NAME UNIQUENES INDEX_TYPE
------------------------------ --------- ------------

---------------
T_IDX NONUNIQUE NORMAL
可以看到我们创建的压根不是唯一性索引,但是可以和普通索引

映射起来。
SQL> SELECT

OWNER,CONSTRAINT_NAME,TABLE_NAME,GENERATED,INDEX_NAME

FROM USER_CONSTRAINTS WHERE TABLE_NAME='T'
OWNER CONSTRAINT_NAME

TABLE_NAME GENERATED

INDEX_NAME
------------------------------ ----------------------

-------- ------------------------------ --------------

------------------------------
TEST T_UNIQUE

T USER NAME

T_IDX
明白了这一点,其实对于理解约束和索引的关系和关联还是很有

帮助的。
个人觉得为什么索引和约束要分开,有一个很大的原因就是因为

约束disable的情况下,索引会连带删除。
SQL> create table test2(id number,name varchar2(30));
Table created.
SQL> alter table test2 add constraint con_test2_id_uq

unique(id);
Table altered.
插入一些数据。
SQL> insert into test2 select object_id,object_name

from all_objects;
72888 rows created.
SQL> commit;
Commit complete.
索引和约束的关系如下:
SQL> select constraint_name,status,index_name from

user_constraints where table_name='TEST2';
CONSTRAINT_NAME STATUS INDEX_NAME
------------------------------ -------- -------------

-----------------
CON_TEST2_ID_UQ ENABLED

CON_TEST2_ID_UQ
把约束置为失效
SQL> alter table test2 disable constraint

con_test2_id_uq;
Table altered.
这个时候再次查看,索引已经没有了踪影,对应的段也不存在了


SQL> select constraint_name,status,index_name from

user_constraints where table_name='TEST2';
CONSTRAINT_NAME STATUS INDEX_NAME
------------------------------ -------- -------------

-----------------
CON_TEST2_ID_UQ DISABLED
如果这个表非常大,这种操作的影响还是非常的大的,如果是分

区表的全局索引那么影响也是全局性的。简单点说还是杀伤力太

大。个人见解而已。

本文标签:
本文标题:约束和索引的关系
网站声明:本文由风哥整理发布,转载请保留此段声明,本站所有内容将不对其使用后果做任何承诺,请读者谨慎使用!
【上一篇】
【下一篇】