【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】 

原文链接:传送门。

在之前的章节,我们把索引看做一组有序条目的集合,每行数据对应一个索引条目。我们解释了很多关于索引逻辑方面的内容,集中在各个条目的数据上以及把它们包含进索引建序列所产生的影响上。因此到目前为止,我们已经涉及了非聚集索引条目的前两个组件:检索键(search key)和包含列(included columns)。本章节我们将检查它的第三个,也是最后一个组件:书签(bookmark)。

书签里是什么?

      之前我们提到过书签,但仅仅是说它使得SQL SERVER从非聚集索引条目快速导航到所交互的行数据上。现在是时候深入书签的更多细节了,毕竟,书签的内容根据其底层表是堆或者是聚集索引而有所不同。

不管表是一个堆或者是一个聚集索引,表中的每一行数据都是其所在页的第N行,所在页都是其所在数据文件的第N个页,那个文件总是组成数据库的文件组的第N个文件。因此,数据库的每一行数据,在任何给定的时刻,都能被三个数字来标识:文件号,页号,行号。这种由三个数字组成的标识称为 行ID(row id),通常简写为RID。显示SQL SERVER内部信息的大部分工具都会以冒号分割的形式来显示这三个数字,因此1号文件的77页的12行数据将会有一个这样的RID: 1:77:12。

一般而言,堆的数据行不会移动,一旦它们被插入进一个页中,便会一直在那个页中。从技术角度更精确的说,堆中的数据行很少移动,当它们确实发生移动时,便会在原来的位置留下跳转地址。然而,聚集索引的数据行可以移动,也就是说,在数据更新或者索引重组时,它们能被重新定位到另一个页。关于数据行被更新时会发生什么的更多细节(包含关于跳转行的信息)将在后续章节给予介绍。

既然堆的数据行不会移动,那么RID 便可以永久的标识堆中的数据行,这个值不仅是恒定的,它也实际确定了行的位置,这使得它成为了在堆的非聚集索引中表示书签值的理想值,这便是SQL SERVER在堆上创建的非聚集索引中使用它(RID)的原因。

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

     我们说表SalesOrderDetail 是一个堆,它的数据行没有特定的顺序,然后我们创建了在第五节使用的索引:在ProductID / ModifiedDate列建立的非聚集索引,并包含了包含列,如下所示:

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

在这个非聚集索引中,按序排列的条目看起来像是这样:

:- Key Columns -:      :---  Included Columns  ---:          : Bookmark :ProductID   ModifiedDate      OrderQty UnitPrice LineTotal
----------- ------------      -------- --------- --------- -------------Page n-1:709         01 Feb 2002       1            5.70       5.70      3:9198:41
709         01 May 2002       1            5.70       5.70      3:969:2
710         01 Jul 2001       1            5.70       5.70      3:9840:29
710         01 Jul 2001       1            5.70       5.70      3:9916:29
710         01 Sep 2001       1            5.70       5.70      4:12331:32Page n:710         01 Oct 2001       1            5.70       5.70      3:1911:33
710         01 Nov 2001       1            5.70       5.70      4:2604:34
710         01 Nov 2001       1            5.70       5.70      4:2889:34
710         01 Nov 2001       1            5.70       5.70      3:3522:35
710         01 Nov 2001       1            5.70       5.70      3:3623:35710         01 Jun 2002       1            5.70       5.70      4:3917:5
712         01 Jul 2001       1            5.19       5.19      3:9886:29
712         01 Jul 2001       1            5.19       5.19      3:10270:29
712         01 Aug 2001       1            5.19       5.19      4:10609:30
712         01 Aug 2001       1            5.19       5.19      4:10617:30Page n+1:712         01 Aug 2001       1            5.19       5.19      4:10689:30
712         01 Aug 2001       1            5.19       5.19      4:10885:30
712         01 Aug 2001       1            5.19       5.19      4:11002:30
712         01 Sep 2001       1            5.19       5.19      4:12318:32
712         01 Sep 2001       1            5.19       5.19      4:509:32

View Code

我们的索引行的书签值非常高效,直接指向交互的数据行,但是它们取决于底层的表是一个堆,尽管这些值对于行查找来说非常高效,但是它们没有包含对于用户来说有价值的信息。

这种基于RID的书签的替代方案便是在聚集索引上创建非聚集索引时会用到的书签。简洁精确的说,便是聚集索引表的非聚集索引所使用的书签。

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

      如果表是一个聚集索引,那么数据行便能在表中重新定位,因此,对于聚集索引来说,RID不能永久标识一个数据行,因而一个不同的值必须被用作此非聚集索引的书签值,这个被用到的值便是聚集索引的索引键。

这解决了需要不变的书签值的需求。因为当聚集索引的一个数据行被移动至新页时,它仅仅被移动,并没有被更新,聚集索引键值便没有变化,因此,此书签值总是可以返回与之交互的行,这就是说数据行会通过索引键返回,而不是通过其实际的物理位置返回。

然而,聚集索引键用作非聚集索引的书签值这种用法意味着聚集索引应该满足三个条件:

 聚集索引必须是唯一的。每一个索引条目书签必须允许SQL SERVER找到与此条目交互的一行数据,如果你创建一个不唯一的聚集索引,SQL SERVER将通过生成额外的值来保证聚集索引的唯一性,这个由SQL SERVER生成的用来保证唯一性的值成为 标识符(uniquifier ),其对任何客户端程序是透明的。基于如下原因,你应该仔细考虑是否允许SQL SERVER在聚集索引中产生重复:

  • 生成标识符需要额外的开销,在插入时,SQL SERVER必须决定,是否新插入的数据行的键与已存在的数据行的键产生重复,如果是,那么便产生标识符加到新行上。
  • 标识符是一条无意义的信息,并且被加在表的非聚集索引中,通常给非聚集索引加上有意义的信息会是更好的做法。

    索引应该简短。也就是说它应该包含少量的字节数,因为它将在所有的非聚集索引中进行传播。Contact 表的 Last name / first name / middle name / street address这几个字段作为聚集索引或许看起来像是一个好主意,但是如果一个表存在多个非聚集索引,它便不是一个好主意了。如果一个表包含N个非聚集索引,那么contact表的 last name / first name / middle name / street address 值便会存储在N+1个位置。

索引应该是静态的。也就是说,它的值应该很少变化,对于一个数据行来说,索引键值的改变强迫各个非聚集索引中此行的条目更新为新键值。因此,对于一个包含N个非聚集索引的表来说,聚集索引键的更改会导致N+1个更改(还不包含 N+1个日志文件的插入)。

当AdventureWorks 数据库的设计团队为SalesOrderDetail 表选择聚集索引时,他们坚持了如上三个指导原则。通过选择SalesOrderID / SalesOrderDetailID 作为聚集索引键达到了窄值,静态以及唯一性的要求。通过添加SalesOrderID 作为索引键的最左列,即使SalesOrderDetailID是唯一的,索引也具有一定的聚集性。一个订单的所有行分组在相同的一两个页上。通过设置SalesOrderID / SalesOrderDetailID 作为表的主键以及聚集索引键,他们消除了在SalesOrderDetailID列上建立单独索引的需求。

没有人会要求去看条目7的数据,他们会要求去看订单#47386的所有条目,或者是订单#47386的#7条目,最重要的是,就如我们说过几次,它使得表处在一个能够最好服务于各个程序的顺序。现在,如果我们在聚集索引表上创建了之前的非聚集索引:

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

View Code

那么此非聚集索引看起来会是这样:

:- Key Columns -:      : ---   Included Columns  ---:    :---   Bookmark   ---:ProductID   ModifiedDate      OrderQty UnitPrice LineTotal      OrderId     DetailId
----------- ------------      -------- --------- ---------      ----------- ----------Page n-1:709         01 Feb 2002       1            5.70       5.70      45329       6392
709         01 May 2002       1            5.70       5.70      46047       8601
710         01 Jul 2001       1            5.70       5.70      43670       111
710         01 Jul 2001       1            5.70       5.70      43676       152
710         01 Sep 2001       1            5.70       5.70      44075       1448Page n:710         01 Oct 2001       1            5.70       5.70      44303       2481
710         01 Nov 2001       1            5.70       5.70      44484       2853
710         01 Nov 2001       1            5.70       5.70      44499       3006
710         01 Nov 2001       1            5.70       5.70      44523       3346
710         01 Nov 2001       1            5.70       5.70      44527       3400710         01 Jun 2002       1            5.70       5.70      46365       10183
712         01 Jul 2001       1            5.19       5.19      43673       136
712         01 Jul 2001       1            5.19       5.19      43694       342
712         01 Aug 2001       1            5.19       5.19      43846       524
712         01 Aug 2001       1            5.19       5.19      43847       528Page n-1:712         01 Aug 2001       1            5.19       5.19      43851       567
712         01 Aug 2001       1            5.19       5.19      43863       672
712         01 Aug 2001       1            5.19       5.19      43871       735
712         01 Sep 2001       1            5.19       5.19      44074       1441
712         01 Sep 2001       1            5.19       5.19      44109       1729

View Code

我们的两个非聚集索引版本:之前在堆上创建的版本和在聚集索引上创建的版本,除了书签的内容不同外,其他地方是完全相同的。

哪一个更好?

       这些设计中的一个比其他的更好吗?或许是吧,但是也好不了太多。基于RID 的书签允许在表中对数据行进行快速查找,索引键书签导致了对应底层表的更慢的数据行查找,但增加了索引覆盖查询的可能性,它通常包含了一个用来做JOIN连接的外键值。

“哪个是更好的?”这个问题的真正答案是:“两者都不”。当为一个表创建索引时,最重要的决策是:哪个索引应该成为表的聚集索引?一旦作出决策(根据本章早些时候提到的指导方案),你不必担心那个决策对于非聚集索引的影响,它们将表现良好。

结论

一个非聚集索引条目包含了检索键,包含列,书签。书签值要么是RID,要么是聚集索引键,这决定于底层表是堆还是聚集索引。对于表来说,选择最合适的聚集索引需要你遵守上述三个指导准则,这样可以确保这个索引键会成为良好的书签值。

转载于:https://www.cnblogs.com/qianxingmu/p/10475468.html

【译】索引进阶(六):SQL SERVER索引书签相关推荐

  1. 翻译:SQL Server中的索引内部结构:到SQL Server索引级别10的阶梯。

    SQL Server中的索引内部结构:到SQL Server索引级别10的阶梯. 大卫•杜兰特2012/01/20 该系列 本文是楼梯系列的一部分:SQL Server索引的阶梯. 索引是数据库设计的 ...

  2. sql索引调优_使用内置索引利用率指标SQL Server索引性能调优

    sql索引调优 描述 (Description) Indexing is key to efficient query execution. Knowing what indexes are unne ...

  3. SQL Server索引进阶第六篇:书签

    SQL Server索引进阶第六篇:书签 索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员 ...

  4. SQL Server索引进阶第十篇:索引的内部结构

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

  5. SQL Server索引总结二

    从CREATE开始 通过显式的CREATE INDEX命令 在创建约束时作为隐含的对象 随约束创建的隐含索引 当向表中添加如下两种约束之一时,就会创建隐含索引. 主键约束(聚集索引) 唯一约束(唯一索 ...

  6. 索引sql server_维护SQL Server索引

    索引sql server In the previous articles of this series (see the full article TOC at bottom), we discus ...

  7. 如何监视SQL Server索引的总大小

    SQL Server索引概述 ( SQL Server indexes overview ) Just like a book index, SQL Server index has a simila ...

  8. sql错误索引中丢失_收集,汇总和分析丢失SQL Server索引统计信息

    sql错误索引中丢失 描述 (Description) Indexing is key to efficient query execution. Determining what indexes a ...

  9. 【译】索引进阶(一):SQL SERVER索引介绍

    [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/7228 ...

  10. 【译】SQL Server索引进阶第八篇:唯一索引

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

最新文章

  1. Android插件化原理解析——ContentProvider的插件化
  2. cd1101d 树形dp
  3. 转载---Adaboost学习记录
  4. Qt工作笔记-在QTreeView上实现模型数据的拖拽
  5. 浅谈云计算三个层次SaaS/PaaS/IaaS
  6. StringBulider StringBuffer
  7. 重磅!激光SLAM算法及框架概述
  8. 年底换机潮来了,都有哪些手机受欢迎?
  9. Origin——在对象管理器中操作图层和绘图
  10. 信息系统项目管理师考试论文写作复习笔记(4)-范围管理论文2
  11. 移动服务器位置,移动协同服务器地址是怎么设置
  12. 象棋( Xiangqi, ACM/ICPC Fuzhou 2011, UVa1589)
  13. 石家庄地铁路线安排网站的设计
  14. Linux XAMP is currently only availably as 32 bit application.
  15. APP平台是怎样实现视频加密呢?
  16. python回归分析结果怎么看_Python数据分析|线性回归
  17. python 路径格式化_吐血整理!140种Python标准库、第三方库和外部工具都有了!...
  18. k个一组翻转链表 哔哩哔哩2020校园招聘笔试题/LeetCode_25(困难)讲解
  19. Win11删除EFI分区
  20. Python实现多电阻并联快捷计算

热门文章

  1. Android getIntent.getString();为空
  2. idea中提示Application context not configured this file 未为此文件配置应用程序上下文
  3. 32位系统加载不了64位的dll。。。是不是没有为此架构安装?
  4. AHK 区域找图功能的使用和实例子
  5. uboot usb启动
  6. 中国海底电缆行业发展前景及投资风险预测分析报告
  7. 中文字型设计新思路--人工智能与中文字型设计
  8. 苹果高调入局中低端市场,国产手机如何“坚守”与“转身”?
  9. Oracle Cloud(甲骨文)开启root登录
  10. 100m光纤测速多少正常_100M,200M,500M,1000M,带宽测速参照表,测试结果(建议收藏)...