背景:                 
[本书目录] [图书首页] [本书讨论区]  
链接地址:http://www.17xie.com/read-105502.html    注册17xie 一起来写书 实现您的出书梦想!

3.5  维护索引

作为开发者,在一个产品交付之后,我们常常会倾向于忘记它。对于许多类型的软件来说,就这样忘掉也没什么不好——你售出了它,然后继续开发下一个产品或下一个版本。然而,对于数据库驱动的项目来说,实际上不可能就这样摆脱它。在交付日期之后,还必须担负起让产品良好工作的责任。

请别以为我的意思是你必须在技术支持部门分担一份工作——其实我讨论的是更重要的事情:维护计划。

实际上,在索引维护方面需要处理两个问题:

l    页拆分;

l    碎片。

这两个问题都与页上的信息密度有关,并且,虽然二者的症状极为不同,但故障排除工具是相同的,因为处理也是相同的。

3.5.1  碎片

前面已经讨论过很多关于页拆分的内容,但实际上还不曾谈到碎片。这里谈论的不是你可能听说过的操作系统文件的碎片以及所使用过的碎片整理工具,它们于数据库碎片没有什么帮助。

在数据库增长、页拆分、然后最终删除数据时,会产生碎片。虽然从增长的视角看,B树机制在保持平衡上确实没那么差。但是,在删除数据时,它的确没做多少贡献。最后,可能会陷入这样的情况:这一页上有一条记录,那一页上有几条记录——在这种情况下,许多数据页上的数据量是它们能够保存的总数据量的一小部分。

或许,关于碎片首先会想到的第一个问题是——浪费的空间。记得前面说过,SQL Server一次分配一个区的空间。只要一页上有一条记录,那么,整个区仍然被分配了。当区中有空的页时,SQL Server将把这些页视为可以在同一个表或索引中重新使用,但是,如果那个表或索引的大小减小了,则区中空闲的页将保持不被使用。

第二个问题是碎片很容易带来麻烦——记录散布在各处会在检索数据时带来额外的开销。SQL Server为了获取10行记录可能必须载入10个不同的页,而不是只载入一个页来获取相同的信息。并不只是行的读取会产生这种结果——SQL Server必须先读入页。更多的页=更多的读取工作量。

话虽如此,数据库碎片也的确有其好的一面——OLTP系统显然偏好碎片。其原因何在?页拆分。没有多少数据的页能够在插入数据时几乎或者完全不担心页拆分。

因此,高碎片等于低读取性能,但也等于卓越的插入性能。正如你可以想见的,这意味着OLAP系统的确不喜欢碎片,但是OLTP系统却很喜欢。

3.5.2  检测碎片

SQL Server始终有一个命令帮助你确定数据库中的页和区有多满。在SQL Server 2005中,微软极大地扩展了这一选择,特别是对用于索引的管理工具的可用性进行了扩展。这样一来,能够使用由这些命令和工具提供的信息,在需要做些什么来维护数据库的问题上进行决策。

实际上,“早期待命的”命令是数据库一致性检查器(DBCC)。事实上,在现在所有的安装系统中,都能发现对该命令以某种形式的使用,将来亦如是。这是2005之前完成任务的方法,并且任何早于2005的数据库安装进行维护时,无论如何都会利用它。另外,网上有大量的文章和教程说明如何使用该工具。

在我盛赞DBCC SHOWCONTIG之前,先坦白说明一下,现在我不再认为它是最好的工具。微软在“sys”系统函数中加入了一些新的功能,在更全局的级别上,能够更明确地查询数据和管理索引,这的确很棒。很快我们将看到在这些方面上与索引相关的内容,并将在讲述管理的一章中更充分地讨论它们。但必须指出,DBCC多年来一直在做这些工作,并且如果监控的索引所在的服务器环境中包含早于SQL Server 2005的安装版本,那么它将是要使用的方法。

语法非常简单:

DBCC SHOWCONTIG

  [({<表名>|<table id>|<视图名>|<view id>}

    [, <索引名>|<index id>])]

  [WITH { [ ALL_INDEXES ]

    | [, FAST ]

    | [, TABLERESULTS ]

    | [, ALL_LEVELS } ]

    | [, NO_INFOMSGS ]

有些东西是不言自明的(例如表名),不过,我想要说明名字之外的一些项:

table id/view id/index id

这是表、视图或索引的内部对象id。在前面版本的SQL Server中,DBCC SHOWCONTIG运行时仅使用标识号,因此在调用DBCC前,必须通过OBJECT_ID()函数查找出对象的标识号

ALL_INDEXES

这是“像它听上去那样”的事物之一。如果指定该选项,则会忽略提供指定的索引,因为将分析所有的索引并返回数据

FAST

这是关于尽可能快地返回的选项,因而它将不分析索引的实际页,并且只输出最少的信息

TABLERESULTS

这是非常棒的功能——它把结果作为表返回而非文本,这意味着分析结果和使用自动化操作将更加容易

ALL_LEVELS

该选项在SQL Server 2005中只有一个实用性,因为它过去做的事情现在已经忽略了。实用性是向后兼容性。基本上,可以包含进该选项,此时命令仍将执行,只是不会有任何不同

NO_INFOMSGS

该选项取消信息性消息。基本上,当表中有任何重大的错误时(错误严重级别11或更高),消息仍会传出,但错误级别10或更低的消息将被排除

举一个例子,要从Sales.SalesOrderDetail表的PK_SalesOrderDetail_SalesOrderID_ SalesOrderDetailID索引中获取信息,可以运行:

注意包围着表名的单引号。因为使用了两部分命名,所以才有如此要求——如果只指定表名(SalesOrderDetail),则不需要引号。这里的问题是,省去模式名可能会产生错误,或者在不同于你预期的表上执行操作,这取决于在使用不同模式时或在不同模式中存在同名的其他表时,用户是如何设置的。

输出实际上不全是自描述的:

其中一些的含义可能非常直接,不过下表将引领你了解所有的输出。

统计信息

说    明

扫描页数

表(用于聚集索引)或索引中的页数

扫描区数

表或索引中的区数。页数的最小值除以8,然后取整。用于同样数目页的区数越多,碎片就越多

区切换次数

遍历表或索引的页时,DBCC从一个区移动到另一个区的次数。这是另一个说明碎片数的信息——看到同样数目的页,所做的切换越多,碎片也越多

每个区的平均页数

每个区的平均页数。完全占用的区有8个页

扫描密度[最佳计数∶实际计数]

最佳计数是指在一切都完美链接的情况下,区更改的理想数目。实际计数是指区更改的实际数目。扫描密度是最佳计数与实际计数的百分比率

逻辑扫描碎片

扫描索引的叶级页时检查到的无序页的百分比。它只与聚集表上的扫描有关。无序页是指索引分配映射(IAM)中指示的下一页与叶级页中下一页指针指向的页不同

区扫描碎片

该信息表示,一个区在物理上的下一个区是否是它在逻辑上的下一个区。这只是说明索引的叶级页在物理上有错(尽管它们在逻辑上是正常的),并给出问题区所占的百分比

页中平均可用字节数

扫描的页上平均可用的字节数。如果行比较大的话,该数值可能会有虚假的较高值。例如,假设行的大小是4040字节,那么每页只能保存一行,因而平均可用字节数将总是4020字节左右。这一数值看似很多,但若要可用,则不能低于给定的行的大小

页的平均密度(全部)

页的平均密度(以百分比表示)。该值会考虑行的大小,因而可以更准确地指示页的填充程度。百分比越高,则越好

现在的问题是,我们一旦得到这些信息,该如何使用呢?答案自然是视情况而定。

使用得自SHOWCONTIG的输出,对于数据库是否满、是否碎片化或者介于中间会有一个适当的认识(后者很可能是我们想看到的)。如果运行的是OLAP系统,那么将愿意看到页面较满——碎片化会让人沮丧。而对于OLTP系统,我们需要的完全相反(尽管只在这一点上)。

那么,如何解决这一问题呢?要回答它,必须了解重新生成索引和填充因子的概念。

DBREINDEX——另一种维护索引的方法

在本章前面讨论过ALTER INDEX命令。这是你的第一条用来执行索引的重新组织和管理碎片化程度的命令。虽然我强烈推荐使用ALTER INDEX,但DBREINDEX曾是过去使用的方法,而且,与DBCC SHOWCONTIG类似,这里有太多的代码和用法已被我忽略。

DBREINDEX是另一个DBCC命令,其语法如下:

DBCC DBREINDEX (<'数据库.所有者.表名'>[, <索引名>

[, <填充因子>]]) [WITH NO_INFOMSGS]

执行该命令将完全重新生成被请求的索引。如果提供的是不带索引名的表名,则会重新生成该表所有的索引。没有单独的命令来重新生成数据库中的所有索引。

重新生成索引将重新构造索引中的所有信息,并重建页填充度的基础百分比。如果讨论中的索引是聚集索引,那么也将会重新组织物理数据。

像使用ALTER INDEX一样,默认情况下,将把页重建为差两条记录填充满。正像使用CREATE TABLE的语法一样,可以把FILLFACTOR设置为0到100之间的任何值。该值是完成数据库重新组织时的页填充度百分比。记得前面说过,在页拆分时,数据将按50-50在两页间分布,但除了规律地重新生成索引外,不能在动态的基础上控制填充度百分比。

当使用0作为填充度百分比时,在满足填充满的数目上多少会有些例外。它将是填充满减去两行(这有点误导——难道不是吗?)。

当需要调整页密度时,可以使用FILLFACTOR。前面已经讨论过,较低的页密度(因而具有较低的FILLFACTOR)对于有很多插入操作的OLTP系统很理想——这有助于避免页拆分。较高的页密度是OLAP系统所需要的(要读取的页较少,由于极少或几乎没有插入,因而实际上没有页拆分的风险)。

对于前面查看过的OrderDetails表,如果想要以65的填充因子重新生成在该表中作为主键的索引,可以发出如下的DBCC命令:

然后,再次运行DBCC SHOWCONTIG,以了解上述命令的效果:

这里需注意的重点是平均页密度上的变化。由于SQL Server必须处理页和行的大小问题,该值并非完全等于65%,但它会尽可能地接近。

关于DBREINDEX和FILLFACTOR要注意如下几件事情:

l    如果没有提供FILLFACTOR,那么DBREINDEX将使用以前创建索引时设置的填充因子。如果从未指定过填充因子,则会把页填充至差两条记录满(这种填充度对大多数情况来说都太满了)。

l    如果提供了FILLFACTOR,则该值将成为那个索引的默认FILLFACTOR。

l    虽然可以当场使用DBREINDEX,但我强烈建议避免使用它——它会锁定资源并带来许多问题。最起码应考虑在非高峰时段进行。如果要在联机的情况下完成该任务,更好的方法是使用ALTER INDEX,且只进行REORGANIZE而不是重新生成。

l    关于这一点,我以前曾经说过,不过需要再重复一次:现在不建议使用DBREINDEX,在不需要向后兼容的情况下,应当避免使用它(请改用ALTER INDEX)。


字数:5050    最后更新:7个月以前 [04-23 15:55]happyskynet 修改
本页编辑者:happyskynet  
[前一页]:3.4 明智地选择:决定…  [后一页]:3.6 小结
[在本页中加入书签] [收藏本书] [推荐本书]
  17xie论坛 > 本书讨论区 > 本页评论   (共0条)
发表评论

用户名称 匿名发表
评论内容
验证码

关于我们 | 版权声明 | 免责声明 | 诚聘英才 | 联系我们 | 合作伙伴 | 友情链接 | 广告合作 | 提交意见
Copyright © 2007 17xie.com 互联网协同写书平台 京ICP备08002671号