索引是我们经常使用的一种数据库搜索优化手段。适当的业务操作场景使用适当的索引方案可以显著的提升系统整体性能和用户体验。在Oracle中,索引有包括很多类型。不同类型的索引适应不同的系统环境和访问场景。其中,唯一性索引Unique Index是我们经常使用到的一种。

唯一性索引unique index和一般索引normal index最大的差异就是在索引列上增加了一层唯一约束。添加唯一性索引的数据列可以为空,但是只要存在数据值,就必须是唯一的。

那么,在使用唯一性索引时,同一般索引有什么差异呢?下面通过一系列的演示实验来说明。

1、实验环境准备

为了体现出一致性和可能的差异性,选择相同的数据值列加入不同类型的索引结构。

SQL> select * from v$version where rownum<2;

BANNER

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

Oracle Database11gEnterpriseEdition Release11.2.0.1.0 - Production

SQL> create table t as select * from dba_objects;

Table created

//保证data_object_id和object_id取值相同;

SQL> update t set data_object_id=object_id;

72581 rows updated

SQL> commit;

Commit complete

//普通索引

SQL> create index idx_t_normalid on t(object_id);

Index created

//唯一性索引

SQL> create unique index idx_t_uniid on t(data_object_id);

Index created

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

2、体积容量比较

在环境准备中,我们将索引列取值设置为完全相同,尽量避免由于外在原因引起的差异。下面我们检查数据字典中的容量比较信息。

首先是查看索引段index segment信息。

SQL> select segment_name, segment_type, bytes, blocks, extents from dba_segments where segment_name in ('IDX_T_NORMALID','IDX_T_UNIID');

SEGMENT_NAME        SEGMENT_TYPE        BYTES    BLOCKS EXTENTS

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

IDX_T_NORMALID      INDEX                 983040       120        15

IDX_T_UNIID           INDEX                 917504       112        14

一般索引normal index较唯一性索引空间消耗略大。索引idx_t_normalid占据15个分区,120个block。略大于idx_t_uniid的14个分区块。

这个地方需要注意一下,在数据字典中一个segment的分区占据,是Oracle系统分配给的空间,并不意味着全部使用殆尽。可能两个索引结构差异很小,但是额外多分配出一个extent。

索引叶子结构上,检查数据字典内容。

SQL> select index_name, index_type, UNIQUENESS, BLEVEL, LEAF_BLOCKS, DISTINCT_KEYS from dba_indexes where index_name in ('IDX_T_NORMALID','IDX_T_UNIID');

INDEX_NAME          INDEX_TYPE     UNIQUENESS    BLEVEL LEAF_BLOCKS DISTINCT_KEYS

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

IDX_T_UNIID         NORMAL         UNIQUE             1        106        51330

IDX_T_NORMALID      NORMAL         NONUNIQUE          1        113        51330

两者的差异不大,normal index空间消耗要略大于unique index。

结论:从数据字典反映出的情况可以知道,同一般索引相比,唯一性索引的空间消耗略小一些。由于我们采用的实验数据都是相同的,这一点点的差距可能就意味着两种索引类型在存储结构上存在略微的差异。

3、违反约束实验

作为唯一性索引,在添加创建和进行dml操作的时候,都会严格发挥出约束的作用。

SQL> insert into t select * from t where rownum<2;

insert into t select * from t where rownum<2

ORA-00001:违反唯一约束条件(SYS.IDX_T_UNIID)

4、等号检索实验

当我们进行等号查询的时候,Oracle对两种索引生成的执行计划有何种差异?注意:下面的select检索之前,都使用flush语句对shared_pool和buffer_cache进行清理。

--精确查询

SQL> select * from t where object_id=1000;

执行计划

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

Plan hash value: 776407697

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

| Id | Operation                  | Name          | Rows | Bytes | Cost (%CPU)| Time    |

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

|  0 | SELECT STATEMENT           |               |    1 |  101 |    2  (0)| 00:00:01 |

|  1 | TABLE ACCESS BY INDEX ROWID| T             |    1 |  101 |    2  (0)| 00:00:01 |

|* 2 |  INDEX RANGE SCAN         | IDX_T_NORMALID |    1 |      |    1  (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("OBJECT_ID"=1000)

统计信息

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

528 recursive calls

0 db block gets

87 consistent gets

11 physical reads

0 redo size

1200 bytes sent via SQL*Net to client

376 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

1 rows processed

SQL> select * from t where data_object_id=1000;

执行计划

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

Plan hash value: 335537167

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

| Id | Operation                  | Name       | Rows | Bytes | Cost (%CPU)| Time    |

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

|  0 | SELECT STATEMENT           |            |    1 |  101 |    2  (0)| 00:00:01 |

|  1 | TABLE ACCESS BY INDEX ROWID| T          |    1 |  101 |    2  (0)| 00:00:01 |

|* 2 |  INDEX UNIQUE SCAN        | IDX_T_UNIID |    1 |      |    1  (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("DATA_OBJECT_ID"=1000)

统计信息

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

528 recursive calls

0 db block gets

86 consistent gets

10 physical reads

0 redo size

1200 bytes sent via SQL*Net to client

376 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

1 rows processed

这里,我们看到了Unique Index的一个特性,就是等号操作时执行计划的差异。对Unique Index而言,进行相等查询的结果只有一行值或者没有,所以没必要进行传统的Index Range Scan操作。此处,执行计划中使用的是Index Unique Scan操作,直接精确定位到指定的记录项目,返回rowid记录。

而一般索引在进行等号检索的时候,通常使用的就是Index Range Scan操作。沿着索引树叶子节点进行水平扫描操作,直到获取索引符合条件索引列值的rowid列表。

从成本上看,两者虽然执行计划操作方式有一定差别,但是成本实际差异不大。CPU成本和执行时间上相同。各种块读操作(逻辑读和物理读)存在一些差异,笔者认为源于两个索引结构的微量区别,这样读取的块数一定有些差异。

5、范围搜索实验

当我们进行索引列的范围搜索时,执行计划和成本有何种差异呢?

--范围匹配

SQL> select * from t where object_id>=1000 and object_id<=1500;

已选择490行。

执行计划

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

Plan hash value: 776407697

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

| Id | Operation                  | Name          | Rows | Bytes | Cost (%CPU)| Time    |

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

|  0 | SELECT STATEMENT           |               |  485 | 48985 |   14  (0)| 00:00:01 |

|  1 | TABLE ACCESS BY INDEX ROWID| T             |  485 | 48985 |   14  (0)| 00:00:01 |

|* 2 |  INDEX RANGE SCAN         | IDX_T_NORMALID|  485 |      |    3  (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("OBJECT_ID">=1000 AND "OBJECT_ID"<=1500)

统计信息

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

528 recursive calls

0 db block gets

158 consistent gets

17 physical reads

0 redo size

23775 bytes sent via SQL*Net to client

728 bytes received via SQL*Net from client

34 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

490 rows processed

SQL> select * from t where data_object_id>=1000 and data_object_id<=1500;

已选择490行。

执行计划

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

Plan hash value: 2700411221

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

| Id | Operation                  | Name       | Rows | Bytes | Cost (%CPU)| Time    |

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

|  0 | SELECT STATEMENT           |            |  485 | 48985 |   14  (0)| 00:00:01 |

|  1 | TABLE ACCESS BY INDEX ROWID| T          |  485 | 48985 |   14  (0)| 00:00:01 |

|* 2 |  INDEX RANGE SCAN         | IDX_T_UNIID |  485 |      |    3  (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("DATA_OBJECT_ID">=1000 AND "DATA_OBJECT_ID"<=1500)

统计信息

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

528 recursive calls

0 db block gets

157 consistent gets

16 physical reads

0 redo size

23775 bytes sent via SQL*Net to client

728 bytes received via SQL*Net from client

34 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

490 rows processed

从实验结果看,两者在进行范围搜索时,执行计划没有差异。两者都是进行Index Range Scan操作。各类型成本基本相同。

6、结论

本篇主要从应用角度,分析Unique Index与一般normal Index的差异。从结果看,Unique Index就是额外添加的唯一性约束。该约束严格的保证索引列的取值唯一性,这在一些数据列上的业务约束实现是很重要的功能。比如一个数据列,不能作为主键,而且允许为空,但是业务上要求唯一特性。这时候使用唯一性索引就是最好的选择。

从执行计划where条件中的表现看,Unique Index和一般normal Index没有显著性的差异。

两者数据基础值一样的情况下,生成索引的体积存在略微的差异,说明在存储结构上两者可能有不同。下面我们来分析一下两类型索引的结构信息。

原文地址:https://www.cnblogs.com/sarahc/articles/2112891.html

唯一索引与非唯一索引区别(UNIQUE INDEX, NON-UNIQUE INDEX)的更多相关文章

  1. SQL Server索引 - 聚集索引、非聚集索引、非聚集唯一索引 <第八篇>

    聚集索引.非聚集索引.非聚集唯一索引 我们都知道建立适当的索引能够提高查询速度,优化查询.先说明一下,无论是聚集索引还是非聚集索引都是B树结构. 聚集索引默认与主键相匹配,在设置主键时,SQL Ser ...

  2. SQL有三个类型的索引,唯一索引 不能有重复,但聚集索引,非聚集索引可以有重复

    重要: (1) SQL如果创建时候,不指定类型那么默认是非聚集索引 (2) 聚集索引和非聚集索引都可以有重复记录,唯一索引不能有重复记录. (3) 主键 默认是加了唯一约束的聚集索引,但是也可以在主键 ...

  3. SQL存储原理及聚集索引、非聚集索引、唯一索引、主键约束的关系(补)

    索引类型 1.          唯一索引:唯一索引不允许两行具有相同的索引值 2.          主键索引:为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型.主键索引要求主键中的 ...

  4. SQL聚集索引和非聚集索引的区别

    其实对于非专业的数据库操作人员来讲,例如软件开发人员,在很大程度上都搞不清楚数据库索引的一些基本知识,有些是知其一不知其二,或者是知其然不知其所以然.造成这种情况的主要原因我觉的是行业原因,有很多公司 ...

  5. 你能说出SQL聚集索引和非聚集索引的区别吗?

    最近突然想起前一阵和一朋友的聊天,当时他问我的问题是一个非常普通的问题:说说SQL聚集索引和非聚集索引的区别. AD:WOT2015 互联网运维与开发者大会 热销抢票 其实对于非专业的数据库操作人员来 ...

  6. mysql 聚集索引,非聚集索引,覆盖索引区别。

    把原站信息经过筛选贴过来,用于自己备忘.原站:https://www.cnblogs.com/aspwebchh/p/6652855.html ---------------------------- ...

  7. SQL Server - 索引详细教程 (聚集索引,非聚集索引)

    转载自:https://www.cnblogs.com/hyd1213126/p/5828937.html 作者:爱不绝迹 (一)必读:深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录. ...

  8. SQLSERVER聚集索引与非聚集索引的再次研究(下)

    SQLSERVER聚集索引与非聚集索引的再次研究(下) 上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 ...

  9. SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>

    一.存储结构 在SQL Server中,有许多不同的可用排列规则选项. 二进制:按字符的数字表示形式排序(ASCII码中,用数字32表示空格,用68表示字母"D").因为所有内容都 ...

  10. 聚集索引VS非聚集索引

    聚集索引VS非聚集索引 SQL Server 2014 发布日期: 2016年12月 索引是与表或视图关联的磁盘上结构,可以加快从表或视图中检索行的速度. 索引包含由表或视图中的一列或多列生成的键. ...

随机推荐

  1. 在Vmware安装虚拟机WindowsServer 2003

    一.创建并安装虚拟机 新建Windows2003server系统 按照下面操作即可 https://www.cnblogs.com/color-blue/p/8525710.html 二.安装虚拟机 ...

  2. JS常用属性方法大全

    1. 输出语句 : document.write(""); 2.JS 中的注释为 : // 3. 传统的 HTML 文档顺序是 : document->html->(h ...

  3. idea展开和折叠方法的快捷键

    Ctrl+"+/-",当前方法展开.折叠 Ctrl+Shift+"+/-",全部展开.折叠

  4. hdu 4027 Can you answer these queries? (区间线段树,区间数开方与求和,经典题目)

    Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K ...

  5. WPF ScrollViewer嵌套Listbox无法滚动

    最近在做项目的时候,发现listBoxzi自带的垂直滚动条有问题,经常在Add(item)的时候下面会多出一些空白的部分,而且滚动条的长度也是无规则的,一会大一会小,而且无法控制横竖滚动条的显隐藏,并 ...

  6. Ubuntu查找通过apt命令已安装软件

    方法一 apt list --installed 方法二 dpkg -l

  7. (实现)vue.js最简实现

    Vue.winward.js vue.js最简实现(the most simple vue.js) 让所有人都看得懂Vue原理 建议看完Vue.winward.js后,结合mpvue源码解读单页应用路 ...

  8. delete records in table A not in table B

    转)A.B两表,找出ID字段中,存在A表,但是不存在B表的数据.A表总共13w数据,去重后大约3W条数据,B表有2W条数据,且B表的ID字段有索引. 方法一 使用 not in ,容易理解,效率低  ...

  9. openssl生成证书 - CSDN博客

    大家都可以生成公钥.私钥对,无法确认公钥对到底是谁的. 如果能够确定公钥到底是谁的,就不会有这个问题了.例如,如果收到“黑客”冒充“服务器”发过来的公钥,经过某种检查,如果能够发现这个公钥不是“服务器 ...

  10. qt,pro文件中用于平台区分的写法

    qt,pro文件中用于平台区分的写法 切记: 大括号和平台需要在同一行中,否则会失效 unix { TARGET = appname } macx { TARGET = appname2 } win3 ...