SQL SERVER 聚集索引 非聚集索引 区别
转自http://blog.csdn.net/single_wolf_wolf/article/details/52915862
一、理解索引的结构
索引在数据库中的作用类似于目录在书籍中的作用,用来提高查找信息的速度。使用索引查找数据,无需对整表进行扫描,可以快速找到所需数据。微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)。
SQL Server 中数据存储的基本单位是页(Page)。数据库中的数据文件(.mdf 或 .ndf)分配的磁盘空间可以从逻辑上划分成页(从 0 到 n 连续编号)。磁盘 I/O 操作在页级执行。也就是说,SQL Server 每次读取或写入数据的最少数据单位是数据页。
下面我们先简单的了解一下索引的体系结构:
1. 聚集索引结构
在 SQL Server 中,索引是按 B 树结构进行组织的。
聚集索引单个分区中的结构:

--建立UserAddDate聚集索引
CREATE CLUSTERED INDEX [IX_AddDate] ON [User]
(
[AddDate] ASC
)
聚集索引(Clustered Index)特点
- 聚集索引的叶节点就是实际的数据页
- 聚集索引中的排序顺序仅仅表示数据页链在逻辑上是有序的。而不是按照顺序物理的存储在磁盘上
- 行的物理位置和行在索引中的位置是相同的
- 每个表只能有一个聚集索引
- 聚集索引的平均大小大约为表大小的5%左右
2. 非聚集索引结构
非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点:
1. 基础表的数据行不按非聚集键的顺序排序和存储。
2. 非聚集索引的叶层是由索引页而不是由数据页组成。
下图示意了单个分区中的非聚集索引结构:

包含列的索引
通过将包含列(称为非键列)添加到索引的叶级,可以扩展非聚集索引的功能。键列存储在非聚集索引的所有级别,而非键列仅存储在叶级别。
下面举个简单的例子来说明一下聚集索引和非聚集索引的区别:
我们有一本汉语字典,可以把它的正文本身看做是一个聚集索引,它是按照汉字拼音的开头字母排序的,不再需要查找其他目录。当遇到不认识的字时,需要结合“部首目录”和“检字表”, 先找到目录中的结果,然后再翻到您所需要的页码。通过这种方法查到的目录中字的排序并不是真正的正文的排序方法。把这种看做是一个非聚集索引。
另外,请注意每个表只能有一个聚集索引。
--建立UserAddDate非聚集索引
CREATE NONCLUSTERED INDEX [IX_AddDate] ON [User]
(
[AddDate] ASC
)
非聚集索引 (Unclustered Index) 特点
- 非聚集索引的页,不是数据,而是指向数据页的页。
- 若未指定索引类型,则默认为非聚集索引。
- 叶节点页的次序和表的物理存储次序不同
- 每个表最多可以有249个非聚集索引
- 在非聚集索引创建之前创建聚集索引(否则会引发索引重建)
二、选择建立哪种索引
1. 何时创建聚集索引更能提高性能
Clustered Index会提高大多数table的性能,尤其是当它满足以下条件时:
独特, 狭窄, 持续增长的,最好是只向上增加。例如:
- Identity
- Date, identity
- GUID (only when using newsequentialid() function)
2. 非聚集索引提高性能的方法
非聚集索引由于B树的节点不是具体数据页,有时候由于这个原因,会导致非聚集索引甚至不如表遍历来的快。但是,非聚集索引有个特性,如果你要查询的内容,在非聚集索引中以及被覆盖到了,则不需要继续到聚集索引,或者RID(heap结构中的行标识符)中去寻找数据了,这时候就可以很大的提高性能,这就是覆盖面(Covering) 的问题。
由于聚集索引叶子节点就是具体数据,所以聚集索引的覆盖率是100%, 通过提高覆盖面来提高性能的问题也就只有非聚集索引(Nonclustered Indexes)才存在。
当查询中所有的columns都包括在index上时,我们说这 index covers the query. Columns的顺序在此不重要(Select 时候的顺序不重要,但是Index 建立的顺序可得小心了)。
在 SQL Server 2005 中,为了提高这种 Covering 带来的好处,甚至可以通过将非键列添加到非聚集索引的叶级别来扩展非聚集索引的功能。
补充:只有查询在具有高度选择性的情况下,非聚集索引才有优势。
三、使用聚集索引或非聚集索引的场景 (注:优先级依次为推荐,应,不应)

四、主键和聚集索引的比较

以下是一些大众点评网中测试使用的示例:
CHECKPOINT
DBCC DROPCLEANBUFFERS
SET STATISTICS IO ON
declare @d datetime
set @d=getdate()
SELECT * FROM User WHERE AddDate>'2008-06-01' AND AddDate<'2008-06-10'
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())
--(45077 行受影响)
--表'User'。扫描计数1,逻辑读取1103 次,物理读取2 次,预读1090 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
--2543
CHECKPOINT
DBCC DROPCLEANBUFFERS
SET STATISTICS IO ON
declare @d datetime
set @d=getdate()
SELECT * FROM User WITH (INDEX=IX_AddDate) WHERE AddDate>'2008-06-01' AND AddDate<'2008-06-10'
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())
--(45077 行受影响)
--表'User'。扫描计数1,逻辑读取45165 次,物理读取133 次,预读141 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
--3860
五、使用索引的代价
- 索引需要占用数据表以外的物理存储空间
- 创建索引和维护索引要花费一定的时间
- 当对表进行更新操作时,索引需要被重建,这样降低了数据的维护速度。
引用: http://kb.cnblogs.com/page/144409/
SQL SERVER 聚集索引 非聚集索引 区别的更多相关文章
- SQL Server 解读【已分区索引的特殊指导原则】(3) - 非聚集索引分区
一.前言 在MSDN上看到一篇关于SQL Server 表分区的文档:已分区索引的特殊指导原则,如果你对表分区没有实战经验的话是比较难理解文档里面描述的意思.这里我就里面的一些概念进行讲解,方便大家的 ...
- MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析
文章出处:http://inter12.iteye.com/blog/1430144 MYSQL的全表扫描,主键索引(聚集索引.第一索引),非主键索引(非聚集索引.第二索引),覆盖索引四种不同查询的分 ...
- 数据库索引--------B/B+树、聚集、非聚集、符合索引
摘录自博客:http://www.cnblogs.com/morvenhuang/archive/2009/03/30/1425534.html 一.引言 对数据库索引的关注从未淡出我的们的讨论,那么 ...
- Mysql 索引实现原理. 聚集索引, 非聚集索引
Mysql索引实现: B-tree,B是balance,一般用于数据库的索引.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.而B+tree是B-tree的一个变种,My ...
- SQL Server查询性能优化——创建索引原则(一)
索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页 就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索 ...
- SQL Server 查询性能优化——创建索引原则(一)(转载)
索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...
- SQL Server 查询性能优化——创建索引原则(一)
索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...
- SQL Server 查询性能优化——创建索引原则
索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...
- SQL Server 解读【已分区索引的特殊指导原则】(2)- 唯一索引分区
一.前言 在MSDN上看到一篇关于SQL Server 表分区的文档:已分区索引的特殊指导原则,如果你对表分区没有实战经验的话是比较难理解文档里面描述的意思.这里我就里面的一些概念进行讲解,方便大家的 ...
随机推荐
- 第十七篇:IO复用之select实现
前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识. 接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这 ...
- Kafka配置SSL(云环境)
本文结合一个具体的实例给出如何在公有云环境上配置Kafka broker与client之间的SSL设置. 测试环境 阿里云机一台(Server端):主机名是kafka1,负责运行单节点的Kafka集群 ...
- es 5.0 拼音分词器 mac
安装方法和ik中文分词器一样, 先下载: https://github.com/medcl/elasticsearch-analysis-pinyin 执行: mvn package; 打包成功以后, ...
- Android学习之蓝牙操作
BluetoothAdapter 用法 蓝牙运行原理:通过BluetoothAdapter 蓝牙适配器处理任务,如果蓝牙被启动之后,系统会自动去搜索其它设备,如果匹配到附近的设备就发送一个广播,Bro ...
- x64枚举DPC定时器
@写在前面 不同于x86,x64的DPC是被加密了的.对于x64DPC的兴趣始于我已经流产的scalpel计划.当时问某牛怎么遍历,得到的答案是“500大洋给代码”.真是R了狗了,好歹小哥我 ...
- 基于链表的C语言堆内存检测
说明 本文基于链表实现C语言堆内存的检测机制,可检测内存泄露.越界和重复释放等操作问题. 本文仅提供即视代码层面的检测机制,不考虑编译链接级的注入或钩子.此外,该机制暂未考虑并发保护. 相关性文章参见 ...
- ios设备唯一标识获取策略
In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02 ...
- C++中三种创建对象的方法【转】
我们都知道C++中有三种创建对象的方法,如下: #include <iostream> using namespace std; class A { private: int n; pub ...
- vuex - 常用命令学习及用法整理
https://vuex.vuejs.org/zh-cn/api.html 命令 用途 备注 this.$store 组件中访问store实例 store.state.a 获取在state对象中的数据 ...
- 熟悉使用ConfigParser库读写配置文件
Python的配置文件 配置文件 setting.ini文件是一个纯文本 [DataBase1] username = admin passwors = root [DataBase2] hostna ...