译】SQL Server索引进阶第六篇:书签

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:
索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其效果适得其反,可以说“成也索引,败也索引”。

本系列文章来自Stairway to SQL Server Indexes

 

书签是什么

    我们已经在前面提到过书签,但仅仅说了书签可以帮助SQL Server快速从非聚集索引条目导向到对应的行,本篇文章开始让我们对书签的探索更进一步.书签的内容实际上是取决于非聚集索引所在表是以堆还是聚集索引存放的。

     不论表是堆结构还是段结构,可以确定的是,表中每一行都是某一页的第N行,这个某一页又是某个数据库文件的第N页,这个某个数据库文件又是构成数据库的文件组的第N个文件,因此,数据库中的每一行,在指定时间都可以由三个数字进行定位:  文件号:页号:行号。这三个数字组合起来就是所谓的RID。很多显示SQL Server内部结构的工具软件都会将这三个数字通过冒号分隔进行显示。比如,文件1的第77页的第12行的RID就是1:77:12。

    通常来说,在堆上的行不会被改变位置。一旦它们被插入某个页中,它们就会一直呆在那。如果要用更严谨的技术术语来说的话:在堆上的行很少移动。如果行被移动的话,它们会在原来的位置留下指向其移动到的位置的指针。而由聚集索引组织的行,是可以被移动的,行在改动数据或是整理索引的时候要被移动位置。更多的细节会在本系列文章后续篇幅进行介绍。

    因为在堆上的行几乎很少移动,所以RID就可以唯一标识某一行。RID的值不仅仅不变,RID所表示行的物理位置也不会变。这使得RID的值更适宜作为书签。这也是为什么SQL Server在堆上建立的非聚集索引的书签都使用RID。

 

堆上的非聚集索引:基于RID的书签

    假如SalesOrderDetail是一个基于堆的表;表中的每行都不是有序的。下面让我们建立以ProductID/ModifiedDate为非聚集索引键并包含OrderQty, UnitPrice, LineTotal三个列的非聚集索引,如代码6.1所示。

CREATE NONCLUSTERED INDEX FK_ProductID_ModifiedDate 
ON 
Sales.SalesOrderDetail(ProductID, ModifiedDate) 
INCLUDE (OrderQty, 
UnitPrice, LineTotal) 

 

代码6.1 建立含有包含列的非聚集索引

  

    在上面索引中,部分数据的顺序如下所示。

index6

 

    上面建立的非聚集索引因为使用了RID作为书签,直接指向对应行所在的物理地址,因此十分高效。但虽然RID值用于键查找非常高效,但书签中包含的值和具体的用户数据无关。

     另一种与这种基于RID的书签不同的书签,是当非聚集索引所在的表包含聚集索引时出现的。更准确的说,这种书签是建立聚集索引上的非聚集索引的书签。

 

在聚集索引上的非聚集索引:基于键值的书签

    如果表是基于聚集索引的,则表内数据可以在表移动。因此,对于聚集索引来说,RID并不能一直不变的定位一个相同的行。因此必须用另外的方法定位行,这个方法就是使用聚集索引的索引键。

    使用聚集索引键作为书签可以使得当数据在页中的行改变时,不需要非聚集索引的书签的值进行变动,因此非聚集索引的键就可以用于去找底层表的数据,意思是根据书签取数据不再基于物理位置,而是基于聚集索引查找。

    然而,以聚集索引键作为非聚集索引的书签最好要聚集索引键满足如下标准:

 

   索引应该具有唯一性. 每一个索引条目书签都应该使得书签可以通过聚集索引的键值唯一的确认表中的一行,如果你创建的聚集索引键值不唯一,SQL Server将会为有重复键值的每一行自动加上一个叫uniquifier的东西使得每一行唯一。这个uniquifier对客户端是透明的。对于是否可以允许聚集索引键重复,你需要考虑以下两点:

    生成uniquifier增加SQL Server插入操作的额外负担,在插入时SQL Server还需要判断插入的值在表中是否唯一,如果不唯一生成uniquifier值再进行插入。
    uniquifier本身对业务数据来说是没有意义的,但是这个uniquifier本身不仅仅需要占用聚集索引键的空间,还同时占用非聚集索引书签的空间。
 

   索引键应该短.索引键所占的字节数应该短.因为这个键还会占用非聚集索引书签的空间。比如Contact表中以Last name / first name / middle name / street组合作为索引键看上去不错,但如果表中存在多个非聚集索引的话情况就有些微妙了。n个非聚集索引使得Last name / first name / middle name / street这些字段被存储在n+1个位置。

    索引键最好不要变动.也就是索引键的值最好不要变动。对于聚集索引键的修改会使得基于这个聚集索引的所有非聚集索引同样进行修改。所以对于聚集索引的一次update会造成n个非聚集索引书签的update+1个聚集索引键值本身的update。

 

    AdventureWorks的设计团队在设计SalesOrderDetail表的聚集索引时就是完全遵循上面的建议。它们选择SalesOrderID / SalesOrderDetailID作为聚集索引键完全满足了窄,短和唯一的要求。将SalesOrderID作为索引键最左边的一列,尽管SalesOrderDetailID是唯一的,这两列组合在一起进行聚集。以SalesOrderID / SalesOrderDetailID作为主键和聚集索引键,就不再需要单独建立SalesOrderDetailID的非聚集索引了。

    现在我们创建和列表6.1所示的非聚集索引一样的索引。唯一的不同是现在这个版本是基于聚集索引而不是堆的。非聚集索引的部分数据如下:

 

index62

 

我们现在有了两个版本的非聚集索引,分别是创建在堆上的非聚集索引和创建在聚集索引上的非聚集索引,唯一的不同就是它们的书签值。

 

哪种更好

     上面两种聚集索引是不是一种要比另一种更好呢?或许吧,但是也要看具体情况。基于RID的书签允许快速的找到底层表中行所在的物理位置,而基于聚集索引的书签找到底层表的行就慢多了,但这个书签还可以作为包含列使用,书签列同时也常常会被当作外键。

     所以对于上面哪种非聚集索引更好的真正答案是”都不是”。当在表上建立索引时,最重要的选择只是使用哪些列作为索引键。一旦你确定了聚集索引列(基于文中所示的三点建议),剩下的非聚集索引所带来的影响就交给SQL Server来处理吧。

 

小结

     非聚集索引包含了索引键列,包含列和书签。书签的值根据所在表是堆还是聚集索引既可以是RID也可以是聚集索引键。对于表上聚集索引的最好选择要基于文中所给的三点指南。



索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其效果适得其反,可以说“成也索引,败也索引”。

本系列文章来自Stairway to SQL Server Indexes

 

书签是什么

    我们已经在前面提到过书签,但仅仅说了书签可以帮助SQL Server快速从非聚集索引条目导向到对应的行,本篇文章开始让我们对书签的探索更进一步.书签的内容实际上是取决于非聚集索引所在表是以堆还是聚集索引存放的。

     不论表是堆结构还是段结构,可以确定的是,表中每一行都是某一页的第N行,这个某一页又是某个数据库文件的第N页,这个某个数据库文件又是构成数据库的文件组的第N个文件,因此,数据库中的每一行,在指定时间都可以由三个数字进行定位:  文件号:页号:行号。这三个数字组合起来就是所谓的RID。很多显示SQL Server内部结构的工具软件都会将这三个数字通过冒号分隔进行显示。比如,文件1的第77页的第12行的RID就是1:77:12。

    通常来说,在堆上的行不会被改变位置。一旦它们被插入某个页中,它们就会一直呆在那。如果要用更严谨的技术术语来说的话:在堆上的行很少移动。如果行被移动的话,它们会在原来的位置留下指向其移动到的位置的指针。而由聚集索引组织的行,是可以被移动的,行在改动数据或是整理索引的时候要被移动位置。更多的细节会在本系列文章后续篇幅进行介绍。

    因为在堆上的行几乎很少移动,所以RID就可以唯一标识某一行。RID的值不仅仅不变,RID所表示行的物理位置也不会变。这使得RID的值更适宜作为书签。这也是为什么SQL Server在堆上建立的非聚集索引的书签都使用RID。

 

堆上的非聚集索引:基于RID的书签

    假如SalesOrderDetail是一个基于堆的表;表中的每行都不是有序的。下面让我们建立以ProductID/ModifiedDate为非聚集索引键并包含OrderQty, UnitPrice, LineTotal三个列的非聚集索引,如代码6.1所示。

CREATE NONCLUSTERED INDEX FK_ProductID_ModifiedDate 
ON Sales.SalesOrderDetail(ProductID, ModifiedDate)
INCLUDE (OrderQty, UnitPrice, LineTotal)

 

代码6.1 建立含有包含列的非聚集索引

  

    在上面索引中,部分数据的顺序如下所示。

index6

 

    上面建立的非聚集索引因为使用了RID作为书签,直接指向对应行所在的物理地址,因此十分高效。但虽然RID值用于键查找非常高效,但书签中包含的值和具体的用户数据无关。

     另一种与这种基于RID的书签不同的书签,是当非聚集索引所在的表包含聚集索引时出现的。更准确的说,这种书签是建立聚集索引上的非聚集索引的书签。

 

在聚集索引上的非聚集索引:基于键值的书签

    如果表是基于聚集索引的,则表内数据可以在表移动。因此,对于聚集索引来说,RID并不能一直不变的定位一个相同的行。因此必须用另外的方法定位行,这个方法就是使用聚集索引的索引键。

    使用聚集索引键作为书签可以使得当数据在页中的行改变时,不需要非聚集索引的书签的值进行变动,因此非聚集索引的键就可以用于去找底层表的数据,意思是根据书签取数据不再基于物理位置,而是基于聚集索引查找。

    然而,以聚集索引键作为非聚集索引的书签最好要聚集索引键满足如下标准:

 

   索引应该具有唯一性. 每一个索引条目书签都应该使得书签可以通过聚集索引的键值唯一的确认表中的一行,如果你创建的聚集索引键值不唯一,SQL Server将会为有重复键值的每一行自动加上一个叫uniquifier的东西使得每一行唯一。这个uniquifier对客户端是透明的。对于是否可以允许聚集索引键重复,你需要考虑以下两点:

  •     生成uniquifier增加SQL Server插入操作的额外负担,在插入时SQL Server还需要判断插入的值在表中是否唯一,如果不唯一生成uniquifier值再进行插入。
  •     uniquifier本身对业务数据来说是没有意义的,但是这个uniquifier本身不仅仅需要占用聚集索引键的空间,还同时占用非聚集索引书签的空间。

 

   索引键应该短.索引键所占的字节数应该短.因为这个键还会占用非聚集索引书签的空间。比如Contact表中以Last name / first name / middle name / street组合作为索引键看上去不错,但如果表中存在多个非聚集索引的话情况就有些微妙了。n个非聚集索引使得Last name / first name / middle name / street这些字段被存储在n+1个位置。

    索引键最好不要变动.也就是索引键的值最好不要变动。对于聚集索引键的修改会使得基于这个聚集索引的所有非聚集索引同样进行修改。所以对于聚集索引的一次update会造成n个非聚集索引书签的update+1个聚集索引键值本身的update。

 

    AdventureWorks的设计团队在设计SalesOrderDetail表的聚集索引时就是完全遵循上面的建议。它们选择SalesOrderID / SalesOrderDetailID作为聚集索引键完全满足了窄,短和唯一的要求。将SalesOrderID作为索引键最左边的一列,尽管SalesOrderDetailID是唯一的,这两列组合在一起进行聚集。以SalesOrderID / SalesOrderDetailID作为主键和聚集索引键,就不再需要单独建立SalesOrderDetailID的非聚集索引了。

    现在我们创建和列表6.1所示的非聚集索引一样的索引。唯一的不同是现在这个版本是基于聚集索引而不是堆的。非聚集索引的部分数据如下:

 

index62

 

我们现在有了两个版本的非聚集索引,分别是创建在堆上的非聚集索引和创建在聚集索引上的非聚集索引,唯一的不同就是它们的书签值。

 

哪种更好

     上面两种聚集索引是不是一种要比另一种更好呢?或许吧,但是也要看具体情况。基于RID的书签允许快速的找到底层表中行所在的物理位置,而基于聚集索引的书签找到底层表的行就慢多了,但这个书签还可以作为包含列使用,书签列同时也常常会被当作外键。

     所以对于上面哪种非聚集索引更好的真正答案是”都不是”。当在表上建立索引时,最重要的选择只是使用哪些列作为索引键。一旦你确定了聚集索引列(基于文中所示的三点建议),剩下的非聚集索引所带来的影响就交给SQL Server来处理吧。

 

小结

     非聚集索引包含了索引键列,包含列和书签。书签的值根据所在表是堆还是聚集索引既可以是RID也可以是聚集索引键。对于表上聚集索引的最好选择要基于文中所给的三点指南。



本文转自CareySon博客园博客,原文链接http://www.cnblogs.com/CareySon/archive/2012/09/07/2674940.html如需转载请自行联系原作者

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
14天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
52 10
|
1月前
|
SQL 存储 数据库
sql事务、视图和索引
sql事务、视图和索引
14 0
|
24天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
17 0
|
14天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
84 6
|
1天前
|
SQL 数据管理 关系型数据库
如何在 Windows 上安装 SQL Server,保姆级教程来了!
在Windows上安装SQL Server的详细步骤包括:从官方下载安装程序(如Developer版),选择自定义安装,指定安装位置(非C盘),接受许可条款,选中Microsoft更新,忽略警告,取消“适用于SQL Server的Azure”选项,仅勾选必要功能(不包括Analysis Services)并更改实例目录至非C盘,选择默认实例和Windows身份验证模式,添加当前用户,最后点击安装并等待完成。安装成功后关闭窗口。后续文章将介绍SSMS的安装。
4 0
|
2天前
|
SQL 关系型数据库 MySQL
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
9 0
|
9天前
|
SQL 安全 网络安全
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
20 0
|
14天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
16天前
|
SQL 数据库 索引
SQL索引失效原因分析与解决方案
SQL索引失效原因分析与解决方案
22 0
|
18天前
|
SQL 数据安全/隐私保护
SQL Server 2016安装教程
SQL Server 2016安装教程
21 1