【译】索引进阶(十一):SQL SERVER中的索引碎片【上篇】

原文链接:传送门。

 

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

一些背景知识 / 复习

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

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

如果表是个堆,那么其非聚集索引的书签部分便是一个行标识符(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') PSJOIN sys.indexes IXON 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...

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/411884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux备份mysql部分表数据,linux mysql 数据按表名称备份

1、按表名称备份#!/bin/bash#user#数据库用户dbuser"root"#数据库密码dbpassword"chenyong"#时间date$(date %Y%m%d)#数据库名称dbnamesungrowv3#备份数据保存的路劲url/home/test/sql/#指定数据库的所以表tables$(mysql -u$dbuser -p$dbpassword -ss -e &…

Maverick.Net介绍 (来自http://www.cnblogs.com/RicCC/archive/2006/09/17/506890.html)

Maverick.Net介绍 Maverick.Net是Java社区开源MVC Web框架Maverick的.Net版本,相关资料可以查看项目主页。不管Maverick.Net的是非好坏,了解一下它的思想还是不错的。下面的内容是对Maverick.Net整体做一个简单的介绍,以求能够从全局的角度了…

惊了!最通俗易懂的Djongo入门竟然在这里!

Django简介python下有多款不同的web框架,Django是最有代表行的一种。许多成功的网站和app都基于djanfo。django是一个开源的web应用框架,由python写成。django采用了MVC的软件设计模式,即模型M,视图V和控制器C。Django特点强大的数据库功能&a…

linux z是什么文件夹,Linux znew初学者命令实例教程

原标题:Linux znew初学者命令实例教程您是否知道Linux提供了一种将.Z文件重新压缩为.gz文件的方法? 是的,znew命令可以让你这样做。 在本教程中,我们将使用一些易于理解的示例讨论此命令行实用程序的基础知识。 但在我们这样做之前…

使用X.509数字证书加密解密实务(一)-- 证书的获得和管理

一、 获得证书... 21、 从CA获得... 22、 从windows2003证书服务中获得... 23、 使用makecert工具获得... 2二、 证书的保存... 21、 保存在证书存储区... 22、 以文件形式保存... 42.1. 带有私钥的证书... 42.2. …

第四届cccc团体程序设计天梯赛

蒟蒻的第一次参加天梯赛,也能也是最后一次参加天梯赛了,下半年打完icpc就要退役了,准备考研复习了 本人的第一次天梯赛,也是本校的第一次天梯赛,由于大家都缺少经验,痛失银奖,只拿了个铜奖回来&…

aix 到 linux的网络,DB2从AIX server上转移(迁移)到linux上-通信/网络-与非网

首先说一下大致情况,就是目前生产环境(AIX server)上边有一数据库 product,现在想迁移到本地做一下测试环境,由于本地服务器只是linux server所以,不可以直接的用backup 和restore恢复。需要用db2look和db2move配合一下来实现迁移…

JVM分析

在运行java进程是,可以通过jps命令查看进程PID,使用java的同居jmap命令可以得到jvm的dump文件; 在网上找了两种方式获取dump文件 获取JVM的dump文件的两种方式:转载来源https://www.cnblogs.com/liu-ke/p/6622350.html【流柯】 1.…

VSTS2008和FTS2008的系统要求好高啊~

系统要求 支持的操作系统: Windows Server 2003; Windows Vista; Windows XP 处理器:1.6GHz Pentium IIIRAM:1 GB 可用物理 RAM内存得1G啊。我玩魔兽世界的内存也只有1G~ 看来以后配新机器内存起码要搞个3-4G 转载于:https://www.cnblogs.com…

linux进行monkey压力测试,App Monkey压力测试(一)

1:常用选项代码如下:--help:打印帮助信息-v:指定打印信息的详细级别,一个 -v增加一个级别 , 默认级别为 0 。2:事件选项复制代码代码如下:-s:指定产生随机事件种子值,相同的种子值产…

[vue] vue组件里的定时器要怎么销毁?

[vue] vue组件里的定时器要怎么销毁? const timer setInterval(() >{ // 某些定时器操作 }, 500); // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。 this.$once(hook:beforeDestroy, () > { clearInterval(timer); })个人简介 我是歌…

退役博主诈尸

菜鸡博主果然退役了,键盘都好久没有碰过了qwq,嘤嘤嘤。 (说不定以后这个博客会成为文化课直播博客qwq,嘤嘤嘤 省选就快到了,我的好py们要加油呀!!!都他喵给我进队qwq 大家要相信自己…

Jython 2.2 发布

Jython 2.2 发布了,这次发布的2.2版本实现了 Python 2.2 以及 2.3。Jython 是Python 的Java实现。无缝地结合了Java类与Python,使用户能以Python语言的语法编写在Java虚拟机上运行的程序。这次版本的新特性包括:new-style classesJava Collec…

工作371-javascript判断数组为空

var data [];if(data&&data.length 0){//data为空数组时,要执行的代码alert("data为空");}

linux组类型,LINUX用户以及用户组

转载博文:https://blog.csdn.net/xietansheng/article/details/800446200、用户、组、文件权限 常用命令:类型举例用户who, whoami, su, useradd, userdel, passwd, usermod, /etc/passwd组groupadd, groupdel, groupmod, /etc/group文件chmod, chown, chgrp其他sudo, exitPS:1…

linux安装Git依赖的包出错,技术|Linux有问必答:如何在Linux上安装Git

问题: 我尝试从一个Git公共仓库克隆项目,但出现了这样的错误提示:“git: command not found”。 请问我该如何在某某发行版上安装Git?Git是一个流行的开源版本控制系统(VCS),最初是为Linux环境开发的。跟CVS或者SVN这些版本控制系…