第7周 非聚集索引

上个星期我讨论了SQL Server里的聚集索引。当你在表上定义了一个聚集索引,你是物理上把你的表数据按提供的聚集键列的顺序存储。在SQL Server里,一个表只能定义一个聚集索引,非聚集索引可以定义多个(最多999个)。

非聚集索引是第二索引,你可以在表上列进行定义。你也可以把非聚集索引与书比较。但是这次你把它认为类似T-SQL 语言参考的书。书本身就是一个聚集索引,不同的T-SQL命令是按它们的名字物理排序的。在书的最后,你会看到一个索引。当你查找一个T-SQL 命令(例如 CREATE TABLE),你可以使用书最后的索引,来找到这个命令详细介绍的位置。

这里书会给你一个查找值——页码,在那里你可以找到这个命令的详细信息。这与SQL Server里(非聚集索引)的概念是一样的:但给你在执行计划里通过非聚集索引访问你的表,SQL Server会在非聚集索引的叶子层给你查找值,你可以用它找到这条记录的更多信息。SQL Server需要用这个查找值做导航,从非聚集索引到聚集索引或堆表里找到记录其他列值,这些列不是非聚集索引的一部分。在SQL Server里这个被称为书签查找(Bookmark Lookup)。我们来看看它的更多细节。

书签查找(Bookmark Lookups)

每次不在查询的执行计划里访问非聚集索引,你查询里的一些列不是非聚集索引的一部分,SQL Server需要在执行计划里进行书签查找操作。下图是一个执行计划里典型的书签查找:

可以看到,SQL Server在Person.Address表里进行非聚集查找操作。另外SQL Server通过键查找(Key Lookup)(聚集的)操作从聚集表获取所有其他列。这个看起来是SQL Server里很酷的功能,但是实际上,书签查找是非常,非常,非常危险的

它们会导致书签查找死锁,性能会受老的过期的统计信息影响,当你与参数嗅探问题(Parameter Sniffing )打交道时也是。书签查找只会在与非聚集索引组合时发生。因此,下星期我们会讨论下在执行计划里如何避免书签查找,还有为什么有时候SQL Server会完全忽略你的近乎完美的非聚集索引。

聚集键依赖关系(Clustered Key Dependency)

像我刚才说过的,SQL Server在非聚集索引的叶子层保存查找值,用来指向存在聚集表或堆表的记录。当你在堆表定义了一个非聚集索引,这个查找值称为行标识者(Row-Identifier)查找值。它是8 bytes长的值,包含记录物理存储的页号(4 bytes),文件号(2 bytes),还有槽号(2 bytes)。

如果你在聚集表上定义你的非聚集索引,SQL Server使用聚集键值作为查找值。这意味你你要认真选择的聚集键列都是每个非聚集索引的一部分。在聚集和非聚集索引之间有着巨大的依赖关系。聚集键基本上是你表里的冗余数据。因此,当你选择聚集键列时,你真的需要认真考虑。因为它的强大依赖性,选择的最佳聚集键应该有3个特性:

  • 唯一的(Unique)
  • 范围小的(Narrow)
  • 静态的(Static)

用心记住它们,因为你的聚集键始终出现在每个非聚集索引里。

小结

非聚集索引对提高你的查询性能非常重要。不好非聚集索引的设计会让你引入书签查找,这会引入巨大的问题和副作用到你的数据库里。如果你想对非聚集索引内部结构有更深入的理解,可以看看索引深入浅出:非聚集索引的B树结构在聚集表

如我答应的,下星期我会讲下使用覆盖非聚集索引(Covering Non-Clustered Indexes)来避免书签查找(Bookmark Lookups)。还有卸载点(Tipping Point),它用来定义SQL Server是否在使用非聚集索引。请继续关注!

时间: 2024-10-09 20:35:08

第7周 非聚集索引的相关文章

聚集索引与非聚集索引的用法举例与使用注意

聚集索引 用法举例 小明需要查找一个人的姓名,知道他在公司的营销部门的1010办公室的4号座位.这个时候如果需要专门为小明建一个聚集索引表就是,以公司部门表内部门名称排序,再以房间总表序号排序,最后以房间详细表的座位表排序,这样就可以最快的找到他要找的人 聚集索引类似于一个字典,我们知道拼音来寻找字,首先我们知道字音节的首字母,从按a-z排序的字典中找到这个字首字母所在的区域,再从这个区域找到韵母所在的区域,当然韵母在字典中也有顺序,最后就可以找到我们想要的字了 注意事项 限制原则 每个表只能有

Mysql 索引实现原理. 聚集索引, 非聚集索引

Mysql索引实现: B-tree,B是balance,一般用于数据库的索引.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.而B+tree是B-tree的一个变种,MySQL就普遍使用B+tree实现其索引结构. 一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上.这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘

聚集索引与非聚集索引

转自:聚集索引和非聚集索引(整理) 官方说法: 聚集索引 一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序. 聚集索引确定表中数据的物理顺序.聚集索引类似于电话簿,后者按姓氏排列数据.由于聚集索引规定数据在表中的物理存储顺序,因此一个表只能包含一个聚集索引.但该索引可以包含多个列(组合索引),就像电话簿按姓氏和名字进行组织一样. 聚集索引对于那些经常要搜索范围值的列特别有效.使用聚集索引找到包含第一个值的行后,便可以确保包含后续索引值的行在物理相邻.例如,如果应用程序执行 的一个查询经

非聚集索引中的临界点(Tipping Point)

什么是临界点? 注意,我要说的问题是非聚集索引的执行计划从Seek+Lookup变成Table/Clustered Index Scan的临界点.SQL Server的访问数据的IO最小单元是页. 我们知道聚集索引的叶级是数据页,非聚集索引的叶级是指向数据行的指针.所以通过聚集索引获取数据时,就是直接访问聚集索引本身,而通过非聚集索引获取数据时,除了访问自身,还要通过指针去访问数据页.这个过程就是RID/Key Lookup.而此Lookup是一个单页操作,即每次使用一个RID/Key,然后去访

主键,组合主键,聚集索引,非聚集索引,唯一索引

前言: 基于Oracle数据库谈谈索引们的问题,以及在什么情况下使用什么索引, 组合主键,怎么根据实际业务需求来定制自己的索引,主键的应用,来提升系统的性能. 1:主键? 在表中唯一的,也是聚集索引.作用于快速查询.该列唯一. Java代码 复制代码 收藏代码 1.ID NUMBER(38,0) PRIMARY KEY NOT NULL, 2:组合主键? 在表中以多个字段组成在表中是唯一的,也是聚集索引.作用于快速查询.该组合列唯一. Java代码 复制代码 收藏代码 1.CREATE TABL

SQL Server性能优化(7)非聚集索引

一,新建测试表 CREATE TABLE [dbo].[Users](     [ID] [int] IDENTITY(1,1) NOT NULL,     [NAME] [char](80) NOT NULL,     [CreatTime] [datetime] NOT NULL ) ON [PRIMARY] 删除默认聚集索引,新建一个在name列上非聚集索引 插入500条数据 查看该表的页的信息 ---开启跟踪标志 DBCC TRACEON(3604,2588) --DBCC TRACEO

聚集索引和非聚集索引

聚集索引 一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序.  聚集索引确定表中数据的物理顺序.聚集索引类似于电话簿,后者按姓氏排列数据.由于聚集索引规定数据在表中的物理存储顺序,因此一个表只能包含一个聚集索引.但该索引可以包含多个列(组合索引),就像电话簿按姓氏和名字进行组织一样.    聚集索引对于那些经常要搜索范围值的列特别有效.使用聚集索引找到包含第一个值的行后,便可以确保包含后续索引值的行在物理相邻.例如,如果应用程序执行 的一个查询经常检索某一日期范围内的记录,则使用聚集索

蛋疼的郁闷——聚集索引扫描、非聚集索引扫描、表扫描区别

聚集索引扫描,首先我们知道数据它是以索引键为叶节点排列起来的树形数据结构,表中每行的数据都附属在索引键中,对这样的表进行数据查找时,最快的方式当然是“聚集索引查找”.什么情况下才是“聚集索引扫描”呢?是当你要查找的数据的条件字段上没有索引时,此时查询执行器将对整个表中的数据挨个的进行读取确认符合查询条件的数据,但当该表上有字段设有聚集索引时,该扫描过程称之为“聚集索引扫描",相反的情况是当该表上没有一个字段设有”聚集索引“时,该扫描过程称之为”表扫描“.其实他们本质上的过程都是一样的,就是挨个的

非聚集索引的注意事项

1.在非聚集索引中包含了对聚集索引的引用.也就是说在非聚集索引页上面保存了聚集索引的一份数据2.当查询包含非聚集索引列的数据时,首先对非聚集索引进行扫描,然后通过非聚集索引找到聚集索引,最后通过聚集索引定位数据3.如果select中包含非聚集索引列(A)和非索引列(B),当通过条件A(Where A)查询B列(Select B)时,过程如下,通过A找到对应的聚集索引Id,在通过ID 定位到磁盘上面的那一行数据,最后读取那一行数据的B列.(操作较复杂,可将B列也包含到非聚集索引中,就不用走这么多流