SQL Server - 聚集索引 <第六篇>

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

  当我们创建主键约束时,如果不存在聚集索引并且该索引没有被明确指定为非聚集索引,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 - 聚集索引 <第六篇>,布布扣,bubuko.com

时间: 2024-10-11 08:48:57

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

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

简介 在SQL Server中,数据是按页进行存放的.而为表加上聚集索引后,SQL Server对于数据的查找就是按照聚集索引的列作为关键字进行了.因此对于聚集索引的选择对性能的影响就变得十分重要了.本文从旨在从性能的角度来谈聚集索引的选择,但这仅仅是从性能方面考虑.对于有特殊业务要求的表,则需要按实际情况进行选择. 聚集索引所在的列或列的组合最好是唯一的 这个原因需要从数据的存放原理来谈.在SQL Server中,数据的存放方式并不是以行(Row)为单位,而是以页为单位.因此,在查找数据时,S

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

主键是一个约束(constraint),他依附在一个索引上,这个索引可以是聚集索引,也可以是非聚集索引. 所以在一个(或一组)字段上有主键,只能说明他上面有个索引,但不一定就是聚集索引. 例如下面: 1 USE [pratice] 2 GO 3 CREATE TABLE #tempPKCL 4 ( 5 ID INT PRIMARY KEY CLUSTERED --聚集索引 6 ) 7 8 9 --------------------------------- 10 USE [pratice] 1

SQL Server 聚集索引在函数中进行转换以至失效(案例)

最近在进行一期的优化,先把数据库中最耗时的前N个语句查询出来! SELECT TOP 10 qp.query_plan,qt.text,total_worker_time from sys.dm_exec_query_stats CROSS APPLY sys.dm_exec_sql_text(sql_handle) qt CROSS APPLY sys.dm_exec_query_plan(plan_handle) qp where qp.query_plan.exist('declare n

SQL Server索引 - 非聚集索引 &lt;第七篇&gt;

一.非聚集索引维护 非聚集索引的行定位器值保持相同的聚集索引值,即使该聚集索引列物理上重新定位后,也是如此. 为了优化这个维护开销,SQL Server添加一个指向旧数据页的指针,以在页面分割之后指向新的数据页面,而不是更新所有相关非聚集索引的行定位器.这样,虽然降低了非聚集索引的维护开销,但是增加了从非聚集索引行到数据行的导航开销,因为添加了一个旧数据页面和信数据页面之间的连接.因此,将聚集索引作为行定位器降低了非聚集索引相关的开销. 二.定义书签查找 当一个查询请求不是优化器选择的非聚集索引

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

前言 上一篇我们分析了数据库中的统计信息的作用,我们已经了解了数据库如何通过统计信息来掌控数据库中各个表的内容分布.不清楚的童鞋可以点击参考. 作为调优系列的文章,数据库的索引肯定是不能少的了,所以本篇我们就开始分析这块内容,关于索引的基础知识就不打算深入分析了,网上一搜一片片的,本篇更侧重的是一些实战项内容展示,希望通过本篇文章各位看官能在真正的场景中找到合适的解决方法足以. 对于索引的使用,我希望的是遇到问题找到合适的解决方法就可以,切勿乱用!!! 本篇在分析出索引的优越性的同时也将负面影响

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

原文:SQL Server调优系列基础篇(索引运算总结) 前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方式可以指导我们如何建立索引.调整我们的查询语句,达到性能优化的目的. 闲言少叙,进入本篇的正题. 技术准备 基于SQL Server2008R2版本,利用微软的一个更简洁的案例库(Northwind)进行解析. 简介 所谓的索引应用就是在我们

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

原文:SQL Server调优系列进阶篇(如何维护数据库索引) 前言 上一篇我们研究了如何利用索引在数据库里面调优,简要的介绍了索引的原理,更重要的分析了如何选择索引以及索引的利弊项,有兴趣的可以点击查看. 本篇延续上一篇的内容,继续分析索引这块,侧重索引项的日常维护以及一些注意事项等. 闲言少叙,进入本篇的主题. 技术准备 数据库版本为SQL Server2012,前几篇文章用的是SQL Server2008RT,内容区别不大,利用微软的以前的案例库(Northwind)进行分析,部分内容也会

深入非聚集索引:楼梯SQL Server二级索引

通过大卫·杜兰特,2017/10/18(第一次出版:2014/11/26) 该系列 本文是楼梯系列的一部分:SQL Server的阶梯索引 索引数据库设计的基础,告诉开发人员使用数据库设计者的意图. 不幸的是索引时往往是后加上的性能问题出现. 终于在这里是一个简单的系列文章,应该让任何数据库专业迅速"加速" SQL Server的一级索引楼梯介绍了SQL Server索引,一般来说,和非聚集索引. 作为我们的第一个案例研究中,我们演示了索引的潜在好处,当从一个表中检索单个行. 在这个层

SQL Server调优系列进阶篇(深入剖析统计信息)

前言 经过前几篇的分析,其实大体已经初窥到SQL Server统计信息的重要性了,所以本篇就要祭出这个神器了. 该篇内容会很长,坐好板凳,瓜子零食之类... 不废话,进正题 技术准备 数据库版本为SQL Server2008R2,利用微软的以前的案例库(Northwind)进行分析,部分内容也会应用微软的另一个案例库AdventureWorks 相信了解SQL Server的朋友,对这两个库都不会太陌生. 概念理解 关于SQL Server中的统计信息,在联机丛书中是这样解释的 查询优化的统计信