DBCC DBREINDEX重建索引提高SQL Server性能

来源:互联网 发布:南京seo哪家好 编辑:程序博客网 时间:2024/06/18 12:06
DBCC DBREINDEX重建索引提高SQL Server性能

 

 

大多数SQL Server表需要索引来提高数据的访问速度,如果没有索引,SQL Server 要进行表格扫描读取表中的每一个记录才能找到索要的数据。索引可以分为簇索引和非簇索引,簇索引通过重排表中的数据来提高数据的访问速度,而非簇索引则通过维护表中的数据指针来提高数据的索引。

 

1. 索引的体系结构

为什么要不断的维护表的索引?首先,简单介绍一下索引的体系结构。SQL Server在硬盘中用8KB页面在数据库文件内存放数据。缺省情况下这些页面及其包含的数据是无组织的。为了使混乱变为有序,就要生成索引。生成索引后,就有了索引页和数据页,数据页保存用户写入的数据信息。索引页存放用于检索列的数据值清单(关键字)和索引表中该值所在纪录的地址指针。索引分为簇索引和非簇索引,簇索引实质上是将表中的数据排序,就好像是字典的索引目录。非簇索引不对数据排序,它只保存了数据的指针地址。向一个带簇索引的表中插入数据,当数据页达到100%时,由于页面没有空间插入新的的纪录,这时就会发生分页,SQL Server 将大约一半的数据从满页中移到空页中,从而生成两个半的满页。这样就有大量的数据空间。簇索引是双向链表,在每一页的头部保存了前一页、后一页地址以及分页后数据移动的地址,由于新页可能在数据库文件中的任何地方,因此页面的链接不一定指向磁盘的下一个物理页,链接可能指向了另一个区域,这就形成了分块,从而减慢了系统的速度。对于带簇索引和非簇索引的表来说,非簇索引的关键字是指向簇索引的,而不是指向数据页的本身。

 

为了克服数据分块带来的负面影响,需要重构表的索引,这是非常费时的,因此只能在需要时进行。可以通过DBCC SHOWCONTIG来确定是否需要重构表的索引。

 

2. DBCC SHOWCONTIG用法

下面举例来说明DBCC SHOWCONTIGDBCC REDBINDEX的使用方法。以应用程序中Employee数据作为例子,在 SQL ServerQuery analyzer输入命令:

use database_name

declare @table_id int

set @table_id=object_id('Employee')

dbcc showcontig(@table_id)

 

输出结果:

DBCC SHOWCONTIG scanning 'Employee' table...

Table: 'Employee' (1195151303); index ID: 1, database ID: 53

TABLE level scan performed.

- Pages Scanned................................: 179

- Extents Scanned..............................: 24

- Extent Switches..............................: 24

- Avg. Pages per Extent........................: 7.5

- Scan Density [Best Count:Actual Count].......: 92.00% [23:25]

- Logical Scan Fragmentation ..................: 0.56%

- Extent Scan Fragmentation ...................: 12.50%

- Avg. Bytes Free per Page.....................: 552.3

- Avg. Page Density (full).....................: 93.18%

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

通过分析这些结果可以知道该表的索引是否需要重构。如下描述了每一行的意义:

信息                                           描述

Pages Scanned                    表或索引中的长页数

Extents Scanned                 表或索引中的长区页数

Extent Switches                  DBCC遍历页时从一个区域到另一个区域的次数

Avg. Pages per Extent         相关区域中的页数

Scan Density[Best Count:Actual Count]       

Best Count是连续链接时的理想区域改变数,Actual Count是实际区域改变数,Scan Density100%表示没有分块。

Logical Scan Fragmentation   扫描索引页中失序页的百分比

Extent Scan Fragmentation    不实际相邻和包含链路中所有链接页的区域数

Avg. Bytes Free per Page       扫描页面中平均自由字节数

Avg. Page Density (full)         平均页密度,表示页有多满

 

 从上面命令的执行结果可以看的出来,Best count23 Actual Count25这表明orders表有分块需要重构表索引。下面通过DBCC DBREINDEX来重构表的簇索引。

 

3. DBCC DBREINDEX 用法

重建指定数据库中表的一个或多个索引。

 

语法

DBCC DBREINDEX

    (    [ 'database.owner.table_name'   

            [ , index_name

                [ , fillfactor ]

            ]

        ]

    )    

 

参数

'database.owner.table_name'

是要重建其指定的索引的表名。数据库、所有者和表名必须符合标识符的规则。有关更多信息,请参见使用标识符。如果提供 database owner 部分,则必须使用单引号 (') 将整个 database.owner.table_name 括起来。如果只指定 table_name,则不需要单引号。

 

index_name

是要重建的索引名。索引名必须符合标识符的规则。如果未指定 index_name 或指定为 ' ',就要对表的所有索引进行重建。

 

fillfactor

是创建索引时每个索引页上要用于存储数据的空间百分比。fillfactor 替换起始填充因子以作为索引或任何其它重建的非聚集索引(因为已重建聚集索引)的新默认值。如果 fillfactor 0DBCC DBREINDEX 在创建索引时将使用指定的起始 fillfactor

 

同样在Query Analyzer中输入命令:

dbcc dbreindex('database_name.dbo.Employee','',90)

 

然后再用DBCC SHOWCONTIG查看重构索引后的结果:

DBCC SHOWCONTIG scanning 'Employee' table...

Table: 'Employee' (1195151303); index ID: 1, database ID: 53

TABLE level scan performed.

- Pages Scanned................................: 178

- Extents Scanned..............................: 23

- Extent Switches..............................: 22

- Avg. Pages per Extent........................: 7.7

- Scan Density [Best Count:Actual Count].......: 100.00% [23:23]

- Logical Scan Fragmentation ..................: 0.00%

- Extent Scan Fragmentation ...................: 0.00%

- Avg. Bytes Free per Page.....................: 509.5

- Avg. Page Density (full).....................: 93.70%

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

通过结果我们可以看到Scan Denity100%

-----------

USE DatabaseName --Enter the name of the database you want to reindex

 

DECLARE @TableName varchar ( 255)

 

DECLARE TableCursor CURSOR FOR

SELECT table_name FROM information_schema . tables

WHERE table_type = 'base table'

 

OPEN TableCursor

 

FETCH NEXT FROM TableCursor INTO @TableName

WHILE @@FETCH_STATUS = 0

BEGIN

DBCC DBREINDEX( @TableName, ' ' , 90)

FETCH NEXT FROM TableCursor INTO @TableName

END

 

CLOSE TableCursor

 

DEALLOCATE TableCursor

 

您可以根据您的需求修改 DBREINDEX 的参数。

需要注意的是,重建非聚集索引时该表会暂时加上共享锁,对用户不可进行 SELECT 以外的操作;重建聚集索引时该表会暂时加上排外锁,不允许任何用户访问。因此需要制定好计划来预防可能的访问问题。

 

REBUILD 有一个 fill factor 参数,如果 fill factor 设置为 100% ,这意味着每一个索引页都是完全满的,如果 fill factor 设置为 50% 意味着每个索引页都是半满的。对于 fill factor 100% ,每次新插入或更新一个记录,由于当前页没有空间可用,可能有分页情况产生。过多的分页会降低 SQL Server 的性能。下面具体举个例子:

假设您在一张表上建立了一个使用默认 fill factor 的新索引。当 SQL Server 创建索引时,它会把索引放置在连续的物理页上,以使数据顺序地被读, I/O 访问最优化。但当表因 INSERT , UPDATE , DELETE 等操作增长改变时,分页发生, SQL Server 在磁盘的其他地方分配新的页,导致新的页与原物理页不连续,增加了随机 I/O ,访问索引页变慢。

 

那么 fill factor 的合适值应该为多少?这取决于表的读 / 写比:

低更新表(读 / 写比: 100 比 1 ): 100% fill factor

高更新表(写超过读): 50%-70% fill factor

居中: 80%-90% fill factor

 

过低的 fill factor 会增加页的数量,也会导致更多的页需要被移至缓存,缓存中有用的数据减少。默认的 fill factor 为 0 (即 100% fill factor ),通常这不是个好的选择,特别是对于聚集索引。

如果您无法判断设置什么 fill factor, 您首先需要确定磁盘的读 / 写比 . 方法就是使用如下两个计数器 :

Physical Disk Object: % Disk Read Time 和 Physical Disk Object: % Write Time 。另外一个可能有用的计数器就是: SQL Server Access Methods: Pages Splits/Sec 。这个计数器测量 SQL Server 内每秒分页的次数。如果该数值过高,您需要降低 fill factor 防止新的分页。

 

如果您想确认您的索引因分页产生的碎片程度,您可以运行 DBCC SHOWCONTIG 命令。如果看特定表和特定索引,您可以运行如下代码:

结果集中最重要的参数是 Scan Density ,越接近 100% 越好。如果 Scan Density 小于 75% ,那么您可能需要重建表中的索引。