原文链接:传送门

第十章节我们分析了索引的内部结构。有了这些关于索引结构的知识,我们便可以分析索引碎片了:其产生的原因,如何防止,以及何时可以不去关注它们。

一些背景知识 / 复习

以下知识对于理解索引碎片来说是至关重要的,有些知识在之前的章节中都已经出现过,比如使用索引来返回数据的场景。在本节,我们的场景是索引的维护,因此,一些旧的知识在此会重复出现,而同时会增加一些新的知识。

每张表要么是个堆要么是个聚集索引。

如果表是个堆,那么其非聚集索引的书签部分便是一个行标识符(RID),如果表是一个聚集索引,那么非聚集索引的书签部分便是其聚集索引的索引键值。

索引条目存储在页中,8个物理上连续的页组成一个区。

索引层级从底部,从0开始计算,因此叶子层级总是第0层,而最低的中间层节点总是第1层,根页总是自己成为一个层级,并且它具有最高的层级数。

扫描整个索引意味着叶子层级的所有页都会被读且仅会被读一次。每一个页包含了一个指向上一个和下一个页的指针。页的逻辑顺序和物理顺序或许是不一致的。指向下一个页的指针后续会指向位于同一个区的页,或者指向几百个页之前的一个页(也可能是之后),甚至于指向不同文件的一个页。

页的物理顺序和逻辑顺序越一致,扫描整个索引所需要的IO数就越少。当两个顺序一致的时候,SQL SERVER每次IO可读取一整个区或者更多。同样的,页的物理顺序和逻辑顺序越相关,那么使用的预读数便越多(预读:在使用之前,先将页存入内存)。不管是扫描整个索引,还是只扫描索引的一部分,这都是确定无疑的。

为了返回一个索引条目,从根节点开始,每个层级的一个页都必须被访问到。这种操作的性能不会被索引物理顺序和逻辑顺序的相关性所影响。

记住了这些信息,我们来检查索引碎片这个主题。

什么是碎片?

索引碎片来自于两种情形:内部碎片和外部碎片。决定索引碎片(不管是内部碎片或者是外部碎片)的最好工具是 sys.dm_db_index_physical_stats这个动态管理函数。因为这个函数显示的是索引ID,而不是索引的名称,查询常常将它与视图sys.indexes 连接起来,从而在输出中包含索引名称,本章节我们将使用这个函数,首先我们梳理下内部碎片,然后再陈述下外部碎片。

 内部碎片

每个页都会包含一定数量的索引条目,那并不意味着每个页总是包含最大数量的条目数。为了本章后续会讲到的一些理由,通常一个索引页并不总是完全充满的。当我们说一个索引包含内部碎片时,我们就意味着这个页并不是完全充满的。在一个索引中,每页占据的空间的数量体现了索引的内部碎片,同时也体现了一个索引的平均页覆盖率。注意覆盖率测量得越高,内部碎片便越少。一个100%充满的页是每有内部碎片的。内部碎片通常以一个百分比的形式被报告出来,并且其体现了字节数上的覆盖率而不是条目上的覆盖率。因此一个覆盖率是96%的索引页或许是完全充满的。那就是说,4%的页空间或许不是足够的空间用来添加一个新的条目。当页的空间被头信息及页的偏移指针占据的时候,一个各个条目相对比较大的页或许在90%,80%,甚至更少的时候就会充满。

sys.dm_db_index_physical_stats函数在它的avg_page_space_used_in_percent输出列报告了索引的内部碎片。显示在列表1的查询,它检查了SalesOrderDetail表的聚集索引,显示了其内部碎片信息。

SELECT IX.name AS 'Name'
, PS.index_level AS 'Level'
, PS.page_count AS 'Pages'
, PS.avg_page_space_used_in_percent AS 'Page Fullness (%)'
FROM sys.dm_db_index_physical_stats(
DB_ID(),
OBJECT_ID('Sales.SalesOrderDetail'),
DEFAULT, DEFAULT, 'DETAILED') PS
JOIN sys.indexes IX
ON IX.OBJECT_ID = PS.OBJECT_ID AND IX.index_id = PS.index_id
WHERE IX.name = 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID';
GO

列表1:  一个返回内部碎片信息的查询

这个查询对于索引的每个层级都会返回一行输出,如图表1中所显示的。

图表1:内部碎片查询的输出

这个特定查询的主题是聚集索引,因此索引的页层级是表的数据行,第0层的输出,也就是以上输出的第一行,告诉我们表的数据行分散在1234个页中,其平均充满率是99%。换句话说,这个表具有很小数量的内部碎片。

外部碎片

与内部碎片相对的,外部碎片指的是一个索引逻辑顺序与物理顺序的不一致。它同样被报告为一个百分比。引用微软技术网的原文,它指的是一个索引的叶子节点中无序页(out-of-order pages)的百分比,所谓的无序页指的是如果当前页物理上分配的紧邻的页不是偏移指针所指向的页。那么当前页便称之为无序页。虽然官方定义将定义本身限制在叶子层级,你将注意到 sys.dm_db_index_physical_stats函数能够返回索引所有层级的碎片信息。

我们注意到,与内部碎片不同的是,一个高的数值意味着更大数量的外部碎片,因此一个具有100%外部碎片的索引几乎完全是外部碎片,也就是说,它的逻辑顺序与物理顺序完全没有任何关联性。

考虑图片2演示的一个简单的例子。一个16个页的索引占据了起始于数据库文件40页和56页的区。除了每个区的最后一个页,任何一个页的下一页指针指向区中的下一页。而第一个区的最后一页指向第二个区的第一页。第二个区的最后一页没有指向任何页,因为其是索引的最后一个页。

在这个例子中,无序页的数量是0,虽然第8,9页在文件中是物理上不连续的,它们在分配给索引的空间内是连续的,因此这个例子的外部碎片是0。

图2: 没有外部碎片的索引

在另一方面,图3展示了一样的表,但是具有一些无序页,前三个页逻辑上是连续的,但是在那之后其逻辑顺序和物理顺序便没有任何相关性。

图3:具有外部碎片的索引

任何下一页指针如果没有指向索引的物理上分配的下一个页的话,便是一个无序指针,不管其向前指,向后指,在区内,跨区,甚至于跨越整个文件。

为了演示如何获取一个索引的外部碎片信息,我们将之前的查询做两处改动。因为外部索引涉及了页之间的关系,而不是页的内容,它能够被扫描索引的第一层定义出来,而不用扫描大得多的索引的叶子层级。我们将函数的最后一个参数从DETAILED 修改为LIMITED (or DEFAULT),从而告知SQL SERVER叶子节点扫描不是必要的。

同时我们修改SELECT子句包含一些稍微不同的列集,它们能够提供索引的外部碎片信息,最终修改后的查询显示如下:

SELECT IX.name AS 'Name'
, PS.index_level AS 'Level'
, PS.page_count AS 'Pages'
, PS.avg_fragmentation_in_percent AS 'External Fragmentation (%)'
, PS.fragment_count AS 'Fragments'
, PS.avg_fragment_size_in_pages AS 'Avg Fragment Size'
FROM sys.dm_db_index_physical_stats(
DB_ID(),
OBJECT_ID('Sales.SalesOrderDetail'),
DEFAULT, DEFAULT, 'LIMITED') PS
JOIN sys.indexes IX
ON IX.OBJECT_ID = PS.OBJECT_ID AND IX.index_id = PS.index_id
WHERE IX.name = 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID';
GO

因为我们给最后一个参数指定了LIMITED,我们将得到一行输出,如图4所示。

图4:外部碎片查询输出

这个结果告诉我们这个索引的大小是1234页,包含了20个碎片,平均每个碎片的大小是61.7页。如同砍一块木头导致两块,砍两下导致3块,一个无序的下一页指针导致两个碎片,两个无序指针导致三个碎片,等等。因此我们的索引含有20-1 =19个页包含无序指针,平均下来,当以逻辑数据扫描这个索引的时候,在各个无序页之间61个连续的页会发生。这是一个包含很少外部碎片的索引。

SSMS的索属性窗口,显示在图5,通过执行一个与我们之前执行的查询类似的查询来获取它的信息,其Page fullnessTotal fragmentation分别指的是索引的内部碎片和外部碎片。

图5:SSMS的索引属性窗口

本节我们介绍了索引碎片的基础知,下一节我们将深入讨论索引碎片,包括其如何产生,如何防止,以及一些通用的实践模式。

To be continued...

【译】索引进阶(十一):SQL SERVER中的索引碎片【上篇】的更多相关文章

  1. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  2. T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他

    简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索 ...

  3. T-SQL查询进阶--理解SQL Server中索引的概念,原理

    简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,sql server仍然可以实现应有的功能,但索引可以在大多数情况下提升查询性能,在OLAP(On line Trans ...

  4. SQL Server中的索引

    1 SQL Server中的索引 索引是与表或视图关联的磁盘上结构,可以加快从表或视图中检索行的速度.索引包含由表或视图中的一列或多列生成的键.这些键存储在一个结构(B 树)中,使 SQL Serve ...

  5. 转载: SQL Server中的索引

    http://www.blogjava.net/wangdetian168/archive/2011/03/07/347192.html 1 SQL Server中的索引 索引是与表或视图关联的磁盘上 ...

  6. 【转】T-SQL查询进阶—理解SQL Server中的锁

      简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查 ...

  7. T-SQL查询进阶—理解SQL Server中的锁

    在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的.这些 ...

  8. sql server中的索引详情

    什么是索引 拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K .为了加快查找的速度,汉语字(词)典一般都有按拼音. ...

  9. 【译】索引进阶(十二):SQL SERVER中的索引碎片【中篇】

    原文链接:传送门. 为了讨论碎片产生的原因,以及避免和移除索引碎片的技术,我们必须从本进阶系列后续将介绍的两个章节借用一些知识点:创建/更新索引的知识,以及向一个索引表插入数据行的相关知识. 当我们讲 ...

随机推荐

  1. protobuf使用详解

    https://blog.csdn.net/skh2015java/article/details/78404235 原文地址:http://blog.csdn.net/lyjshen/article ...

  2. 原生sql整理

    mysql -uroot -p #登录mysql命令password: #输入密码 mysql> #每条mysql命令后面都要加分号结尾show databases; #打印整个mysql数据库 ...

  3. A Base Class pointer can point to a derived class object. Why is the vice-versa not true?

    问题转载自:https://stackoverflow.com/questions/4937180/a-base-class-pointer-can-point-to-a-derived-class- ...

  4. Python基础:语法基础(3)

    本篇主要介绍Python中一些基础语法,其中包括:标识符.关键字.常量.变量.表达式.语句.注释.模块和包等内容. 1. 标识符和关键字 1.1 标识符 标识符是变量.常量.函数.属性.类.模块和包等 ...

  5. delphi7 编译的程序在win7下请求获得管理员权限的方法

    网上找到的,记下来方便查找,亲测此方法可用.附带把编译好的uac.res上传. 首先,用记事本新建一文本文档,内容如下: 1 24 UAC.manifest 然后另存为uac.rc 另外新建一文本档, ...

  6. Django相关问题

    遇到models模型变动后无法用migrations生成改动后的表通过以下几个方面实现 1 python  manage.py makemigrations yourapp(你改变的app) 2  p ...

  7. Mac OSX下安装dlib (Python)

    1.在安装Dlib库之前需要安装的库:opencv,numpy 2.安装Xquartz2.7.11 Xquartz是执行Unix程序的图形窗口环境,为了兼容Unix和Linux下移植过来的程序就需要安 ...

  8. Navicat 连接远程服务器mysql 长时间不操作会连接很久

    服务器mysql 配置 本地mysql客户端配置 √ navicat 连接配置 右键连接,编辑连接,高级,保持连接间隔勾选,把240改为30,确定

  9. 基于H5的混合开发介绍(一)WebView

    转自: https://www.cnblogs.com/sanchang/p/9261461.html 一 WebView到底是什么    1 WebView是一种控件,它基于webkit引擎,因此具 ...

  10. Docker proxy

    Method One: mkdir /etc/systemd/system/docker.service.dvim /etc/systemd/system/docker.service.d/http- ...