聚集索引的叶子页存储的就是表的数据。因此,表行物理上按照聚集索引列排序,因为表数据只能有一种物理顺序,所以一个表只能有一个聚集索引。

  当我们创建主键约束时,如果不存在聚集索引并且该索引没有被明确指定为非聚集索引,SQL Server会自动将其创建为唯一的聚集索引,这并不是说主键列就一定是聚集索引,这只是默认行为而已。

  示例,建表时通过指定主键为非聚集索引使主键列不为聚集列:

CREATE TABLE MyTableKeyExample
{
  Column1 int IDENTITY PRIMARY KEY NONCLUSTERED,
  Column2 int
}

一、堆表与聚集表

  没有聚集索引的表称为堆表。堆表的数据列没有任何特别的顺序,连接到表的相邻页面。与访问大的聚集表相比,对标这种无组织的结构通常增大了访问大的堆表的开销。

  有聚集索引的表称为聚集表,聚集表是B树结构,数据量大时,能够大幅减少读次数。

二、与非聚集索引的关系

  SQL Server中聚集索引和非聚集索引之间有一个有趣的关系,非聚集索引的一个索引列包含指向表的对应数据行的指针。这个指针被称为行定位器。行定位器的值取决于数据表是堆表还是聚集表。当时堆表时,行定位器是指向堆中数据行的RID指针。对于具有聚集索引的表,行定位器是聚集索引键值。

  下面用一个表格来说明这种关系

  假设有一个2列的表:

RID(这不是实际列) 列1 列2
1 A1 A2
2 B1 B2

  堆表:  

索引列(列1) 行定位器
A1 RID = 1 指向表中第一行数据
B1 RID = 2 指向表中第二行数据

  聚集表,假设我们将列2设为聚集索引列:

索引列(列1) 行定位器
A1 A2 指向聚集键
B1 B2 指向聚集键

  由此可见,通过非聚集索引列查找一行数据,还需要多一步-通过RID获得实际数据。这个RID在堆表是行指针,在聚集表是聚集键值。

三、聚集索引的建议

  1、首先创建聚集索引

  对于聚集表而言,因为所有非聚集索引在其索引行上都保存一个聚集索引键值,所以非聚集索引和聚集索引创建的顺序非常重要。如果非聚集索引先于聚集索引创建,那么非聚集索引的行定位器将包含指向堆表的RID的指针。然后再创建聚集索引时,会将所有非聚集索引的RID指针改为聚集键,这实际上相当于重新建立了非聚集索引。
  为了最好的性能,最好在创建任何非聚集索引之前创建聚集索引。这将使得非聚集索引在创建的时候将他们的行定位器直接设置为聚集索引值。这对最终的性能没有太大影响,但是SQL Server工作量少很多,速度快很多。如果你是在线上运行着的系统进行维护操作,这尤其有用。

  2、保持窄索引

  因为所有的非聚集索引将聚集索引键作为行定位器,为了最佳的性能,应使聚集索引的总体长度尽可能小。

  试想,假如创建了个宽的聚集索引,如CHAR(500),这将在每个非聚集索引中添加一个500字节的值。就算非聚集索引什么都不放,光聚集索引键值占用的空间,它一页的数据页仅仅能存放16个数据行左右。

  保持窄聚集索引能有效减少逻辑读操作与磁盘I/O。

  3、一步重建聚集索引

  因为聚集索引上有非聚集索引的依赖性,用单独的DROP INDEX 和 CREATE INDEX语句重建聚集索引将导致所有非聚集索引被重建两次(DROP,行定位器指向堆表数据行指针,CREATE行定位器指向新的聚集键值)。为了避免这种情况,使用CREATE INDEX语句的DROP_EXISTING子句来在一个单独的原子步骤中重建聚集索引。相似地,也可以在非聚集索引上使用DROP_EXISTING子句。

  CREATE CLUSTERED INDEX index1 ON PersonTenThousand(Id) WITH (DROP_EXISTING = ON) 

  4、何时使用聚集索引

  在某些情况下,使用聚集索引是非常有帮助的。

  1、检索一定范围的数据

  因为聚集索引的叶子页面就是表的实际数据,聚集索引列的顺序就是表中数据行的物理顺序。如果数据行的物理顺序与查询请求的数据顺序相同,磁盘刺头可以顺序地读取所有行,而不需要太多的磁头移动。

  假设我聚集索引建立在ID列,我需要读取ID BETWEEN 1 AND 100或ID > 100的数据,那么所有数据行在磁盘上排列在一起。这使磁头可以移动到磁盘上第一行的位置,然后用最少的磁头移动顺序读出所有数据。另一方面,如果行在磁盘上没有以正确的物理顺序排列,磁头必须随机地从一个位置移动到另一个位置来读取所有相关的行。磁头的物理移动是磁盘操作开销的最主要部分,将行以合适的物理顺序在磁盘上排序(使用聚集索引)优化了I/O开销。

  2、读取预先排序的数据

  聚集索引在数据读取需要排序时特别有效,如果在可能需要排序的一列或多列上创建一个聚集索引,那么行将被按该顺序物理排序,这消除了数据读取之后排序的开销。

  在没有聚集索引的情况下,检索范围排序的数据:

  

  在有聚集索引的情况下,检索范围排序的数据:

  

  从中看到,有聚集索引的范围排序返回数据非常快速,因为对于聚集列,本身就是已经排好顺序存放于数据库中的。

  5、何时不使用聚集索引

  在某些情况下,最好不使用聚集索引。

  1、频繁更新的列

  如果聚集索引列频繁更新,将导致所有非聚集索引行的行定位器相应更新,从而显著地增加相关操作查询的开销。还将阻塞这段时间引用相同部分和非聚集索引的其他查询,从而影响数据库的并行性。因此,应该避免在大量更新的列上创建聚集索引。

  2、宽的关键字

  因为所有非聚集索引将聚集键作为其行定位器,所以为了性能,应该避免在非常宽或太多列上创建聚集索引。上面红色加粗字体特别说明了原因。

  3、太多并行的顺序插入

  如果希望并发地添加许多新行,那么对于性能来讲,将他们分布到表的各个数据页面更好一些。但是,如果将所有行按照与聚集索引相同的顺序添加,那么所有的插入操作都在表的最后一个页面上进行。这可能在磁盘的对应山区造成一个巨大的“热点”,为了避免磁盘热点,不应该将数据行按照物理位置相同的顺序排列。可以通过创建另一列上的索引(该索引不会将行按照新航相同的顺序来排列)来插入操作随机地分布到整个表。这个问题只在大量同时插入时发生。

  允许在表的尾部插入,能够避免需要容纳新行时发生的页拆分。如果并行插入数据降低,那么按照新行的顺序来排列数据行(使用聚集索引)将避免页拆分。但是,如果磁盘热点成为性能瓶颈,那么新行可以通过降低表的填充因子来容纳到中间页面。另外,“热”的页面将在内存中,这也有利于性能。

最后附上一个设置非主键为聚集索引列的方法:

1. 查看所有的索引,默认情况下主键上都会建立聚集索引

  查看索引:
  sp_helpindex person
  查看约束:
  sp_helpconstraint person

2. --删除主键约束,把【1】中查询出的主键上的索引约束【如:PK__person__117F9D94】去除掉。去掉主键字段上面的主键约束,此时该字段不是主键了。
  alter table person drop constraint PK_Person

3.--创建聚集索引到其它列

  create clustered index test_index on person(Name)

4.—修改原来的主键字段还是为主键,此时会自动建立非聚集索引【因为已经有了聚集索引】

sp_helpindex person
sp_helpconstraint person
alter table person drop constraint PK_Person
create clustered index test_index on person(Name)
alter table person add primary key (id)

  alter table person add primary key (id)

  

SQL Server - 聚集索引 <第六篇>的更多相关文章

  1. Sql Server 聚集索引扫描 Scan Direction的两种方式------FORWARD 和 BACKWARD

    最近发现一个分页查询存储过程中的的一个SQL语句,当聚集索引列的排序方式不同的时候,效率差别达到数十倍,让我感到非常吃惊 由此引发出来分页查询的情况下对大表做Clustered Scan的时候, 不同 ...

  2. 浅谈sql server聚集索引与非聚集索引

    今天同事的服务程序在执行批量插入数据操作时,会超时失败,代码debug了几遍一点问题都没有,SQL单条插入也可以正常录入数据,调试了一上午还是很迷茫,场面一度很尴尬,最后还是发现了问题的根本,原来是另 ...

  3. SQL SERVER 聚集索引 非聚集索引 区别

    转自http://blog.csdn.net/single_wolf_wolf/article/details/52915862 一.理解索引的结构 索引在数据库中的作用类似于目录在书籍中的作用,用来 ...

  4. 从性能的角度谈SQL Server聚集索引键的选择

      简介 在SQL Server中,数据是按页进行存放的.而为表加上聚集索引后,SQL Server对于数据的查找就是按照聚集索引的列作为关键字进行了.因此对于聚集索引的选择对性能的影响就变得十分重要 ...

  5. SQL server 聚集索引与主键的区别

    主键是一个约束(constraint),他依附在一个索引上,这个索引可以是聚集索引,也可以是非聚集索引. 所以在一个(或一组)字段上有主键,只能说明他上面有个索引,但不一定就是聚集索引. 例如下面: ...

  6. Sql Server聚集索引创建

    create CLUSTERED index IX_ZhuiZIDList_ZID on ZhuiZIDList (ZID)

  7. SQL Server调优系列基础篇(索引运算总结)

    前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...

  8. SQL Server调优系列进阶篇(如何索引调优)

    前言 上一篇我们分析了数据库中的统计信息的作用,我们已经了解了数据库如何通过统计信息来掌控数据库中各个表的内容分布.不清楚的童鞋可以点击参考. 作为调优系列的文章,数据库的索引肯定是不能少的了,所以本 ...

  9. SQL Server调优系列进阶篇(如何维护数据库索引)

    前言 上一篇我们研究了如何利用索引在数据库里面调优,简要的介绍了索引的原理,更重要的分析了如何选择索引以及索引的利弊项,有兴趣的可以点击查看. 本篇延续上一篇的内容,继续分析索引这块,侧重索引项的日常 ...

随机推荐

  1. 《Programming WPF》翻译 第7章 7.我们进行到哪里了?

    原文:<Programming WPF>翻译 第7章 7.我们进行到哪里了? WPF提供了一个范围的高质量生成和合成服务.一组形状元素支持各种的绘图基础.一些笔刷类型是可利用的,对于决定如 ...

  2. ASCII码、base64编码 为什么有的代码要用 base64 进行编码?

    百度百科 ASCII码:http://baike.baidu.com/link?url=bNtzytBhlSUt_l3pwpfICxCxqgAfqsBMaeWX6QF7gH46Tg4pQtKM2aAV ...

  3. 用dTree组件生成无限级导航树

     在做管理系统时不可避免要用到导航树,这种东西只要一次做好,就可以随处运行,目前比较好的组件是dTree,原则上可以达到无限级,当然实际运行中4,5级就已经很多了,dTree的速度还是不错的,而且是J ...

  4. Max Sum of Max-K-sub-sequence(单调队列)

    Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  5. Git的一些用法(建立新的branch)

    建立新的branch和查看全部的branch(kk的代码是基于现有的branch) 切换到branch kk: 当然我们也能够在android studio里操作: 注意切换的时候代码会丢失,必须先c ...

  6. Leetcode 238 Product of Array Except Self 时间O(n)和空间O(1)解法

    1. 问题描写叙述 给定一个n个整数的数组(n>1n>1)nums,返回一个数组output,当中的元素outputioutput_i的值为原数组nums中除numsinums_i之外的全 ...

  7. 初次使用SVN心得

    进入实验室, 一个项目往往需要多天多人次共同维护,所以版本控制也显得尤为关键.下面是我第一次使用SVN工具的心得体会. 首先是安装,服务器搭配方面应该是之前完成的,这里就不多讲了. 下载地址:http ...

  8. Timer.5 - Synchronising handlers in multithreaded programs

    This tutorial demonstrates the use of the boost::asio::strand class to synchronise callback handlers ...

  9. eclipse安装Flash Builder 4后变成中文,怎么解决

    修改eclipse.ini启动参数: -startup plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar --launcher.libr ...

  10. Global.asax使用1

    Application_start: 1.第一个访问网站的用户会触发该方法.(针对访问的是asp.net应用程序的类,及ashx,aspx等才会触发) 2. 通常会在该方法里定义一些系统变量,如聊天室 ...