SQLServer 2008 索引碎片和解决方法

浏览 : 11618 次 Sat, 27 Sep 2014 00:21:55 GMT

毫无疑问,给表添加索引是有好处的,你要做的大部分工作就是维护索引,

在数据更改期间索引可能产生碎片,所以一些维护是必要的。碎片可能是你查询产生性能问题的来源。  

那么到底什么是索引碎片呢?索引碎片实际上有

2种形式:外部碎片和内部碎片。不管哪种碎片基本上都会影响索引内页的使用。这也许是因为页的逻辑顺序错误(即外部碎片)或每页存储的数据量少于数据页的容量(内部错误)

无论索引

产生了哪种类型的碎片,你都会因为它而面临查询的性能问题。 

外部碎片 

当索引页不在逻辑顺序上时就会产生外部碎片。索引创建时,索引键按照逻辑顺序放在一组索引页上。当新数据插入索引时,新的键可能放在存在的键之间。了让新的键按照正确的顺序插入,可能会创建新的索引页来存储需要移动的那些存在的键。这些新的索引页通常物理上不会和那些被移动的键原来所在的页相邻。创建新页的过程会引起索引页偏离逻辑顺序。 

下面的例子将比实际的言论更加清晰的解释这个概念。 

假定在任何另外的数据插入你的表之前存在索引上的结构如下 

(注:下面图片里应该是78,原文里是68):

 

SQLServer索引碎片和解决方法 - 鹰击长空 - 向左向右

 

INSERT语句往索引里添加新的数据,假定添加的是5

INSERT将引起新页创建,为了给5在原来的页上留出空间,78被移到了新页上。这个创建将引起索引页偏离逻辑顺序。 

 

 

SQLServer索引碎片和解决方法 - 鹰击长空 - 向左向右

  

在有特定搜索或者返回无序结果集的查询的情况下,偏离顺序的索引页不会引起问题。对于返回有序结果集的查询,搜索那些无序的索引页需要进行额外的处理。有序结果集的例子如查询返回410之间的记录。为了返回

78,查询不得不进行额外的页切换。虽然一个额外的页切换在一个长时间运行里是无关紧要的,然而想象一下一个有好几百页偏离顺序的非常大的表的情形。 

 

内部碎片 

当索引页没有用到最大量时就产生了内部碎片。虽然在一个有频繁数据插入的应用程序里这也许有帮助,然而设置一个fill factor(填充因子)会在索引页上留下空间,服务器内部碎片会导致索引尺寸增加,从而在返回需要的数据时要执行额外的读操作。这些额外的读操作会降低查询的性能。 

怎样确定索引是否有碎片?

SQLServer提供了一个数据库命令――DBCC SHOWCONTIG――来确定一个指定的表或索引是否有碎片。  

DBCC SHOWCONTIG 数据库平台命令,用来显示指定的表的数据和索引的碎片信息。 

DBCC SHOWCONTIG 权限默认授予 

sysadmin固定服务器角色或 db_owner  db_ddladmin

固定数据库角色的成员以及表的所有者且不可转让。

语法(SQLServer2008 

DBCC SHOWCONTIG  

[ ( { table_name | table_id| view_name | view_id }  

[ , index_name | index_id ]  

)  

]  

[ WITH { ALL_INDEXES  

| FAST [ , ALL_INDEXES ]  

| TABLERESULTS [ , { ALL_INDEXES } ]  

[ , { FAST | ALL_LEVELS } ]  

]

 

语法(

SQLServer7.0

 

 

DBCC SHOWCONTIG  

[ ( table_id [,index_id ]  

)  

]

 

示例: 

显示数据库里所有索引的碎片信息 

SET NOCOUNT ON 

USE pubs 

DBCC SHOWCONTIG WITH ALL_INDEXES 

GO 

 

显示指定表的所有索引的碎片信息 

SET NOCOUNT ONUSE pubs 

DBCC SHOWCONTIG (authors) WITH ALL_INDEXES 

GO 

 

显示指定索引的碎片信息 

SET NOCOUNT ON 

USE pubs 

DBCC SHOWCONTIG (authors,aunmind) 

GO 

 

结果集  

DBCC SHOWCONTIG

将返回扫描页数、扫描扩展盘区数、遍历索引或表的页时,DBCC 句从一个扩展盘区移动到其它扩展盘区的次数、每个扩展盘区的页数、扫描密度

(最佳值是指在一切都连续地链接的情况下,扩展盘区更改的理想数目)。 

DBCC SHOWCONTIG 

正在扫描 'authors' ...

: 'authors'

1977058079

); 

索引

 ID: 1

,数据库 ID: 5 已执行 TABLE 级别的扫描。 

扫描页数.....................................: 1

扫描扩展盘区数...............................: 1

扩展盘区开关数...............................: 0 

每个扩展盘区上的平均页数.....................: 1.0 

扫描密度[最佳值:实际值]....................: 100.00%1:1 

逻辑扫描碎片.................................: 0.00% 

扩展盘区扫描碎片.............................: 0.00%  

每页上的平均可用字节数.......................: 6010.0 

平均页密度(完整)...........................: 25.75% 

DBCC 执行完毕。如果 DBCC 

输出了错误信息,请与系统管理员联系。 

 

寻找什么 

 

扫描页数:

如果你知道行的近似尺寸和表或索引里的行数,那么你可以估计出索引里的页数。看看扫描页数如果明显比你估计的页数要高说明存在内部碎片。 

扫描扩展盘区数:

用扫描页数除以8,四舍五入到下一个最高值。该值应该和DBCC SHOWCONTIG

返回的扫描扩展盘区数一致。如果DBCC SHOWCONTIG返回的数高,

说明存在外部碎片。碎片的严重程度依赖于刚才显示的值比估计值高多少。 

扩展盘区开关数:

该数应该等于扫描扩展盘区数减1。高了则说明有外部碎片。 

每个扩展盘区上的平均页数:

该数是扫描页数除以扫描扩展盘区数,一般是8小于8说明有外部碎片。 

扫描密度[最佳值实际值]:DBCC SHOWCONTIG返回最有用的一个百分比。这是扩展盘区的最佳值和实际值的比率。该百分比应该尽可能靠近100%。低了则

说明有外部碎片。 

逻辑扫描碎片:无序页的百分比。该百分比应该在0%到10%之间,高了则说明有外部碎片。 

扩展盘区扫描碎片:无序扩展盘区在扫描索引叶级页中所占的百分比。

该百分比应该0%,高了则说明有外部碎片。 

每页上的平均可用字节数:所扫描的页上的平均可用字节数。越高说明有内部碎片,不过在你用这个数字决定是否有内部碎片之前,应该考虑fill factor

(填充因子)。 

平均页密度(完整):每页上的平均可用字节数的百分比的相反数。低的百分比

说明有内部碎片。 

 

备注 

DBCC SHOWCONTIG

实际上仅对那些大表有用。小表显示的结果根本不符合正常标准,因为他们也许没有由多于8个的页面组成。你在查看小表上执行DBCC SHOWCONTIG

的结果时应该忽略一些结果。在处理小表时只需关心扩展盘区开关

数、逻辑扫描碎片、每页上的平均可用字节数、平均页密度(完整)。 

DBCC SHOWCONTIG

默认输出的结果是:扫描页数、扫描扩展盘区数、扩展盘区开

关数、每个扩展盘区上的平均页数、扫描密度[最佳值实际值]、逻辑扫描碎片、扩展盘区扫描碎片、每页上的平均可用字节数、平均页密度(完整)。可以

FASTTABLERESULTS选项来控制这个输出结果。FAST选项指定执行索引的快速扫描,输出结果是最小的,该选项不读索引的叶或数据页且只返回扫描页数、扫描扩展盘区数、扫描密度[最佳值:实际值]、逻辑扫描碎片。 

TABLERESULTS选项将用行集的形式显示信息,将返回扩展盘区开关数、扫描密度[最佳值:实际值]、逻辑扫描碎片、扩展盘区扫描碎片、每页上的平均可用字节数、平均页密度(完整)。如果既指定FAST选项又指定TABLERESULTS

选项,那么将返回对象名、对象ID索引名、索引ID,页数、扩展盘区开关数、扫描密度[最佳值:实际值]和逻辑扫描碎片。   ALL_INDEXES选项将显示指定表和试图的所有索引的结果,即使指定了一个索引。  ALL_LEVELS

选项指定是否为所处理的每个索引的每个级别产生输出(默认只输出索引的页级或表数据级的结果),并且只能与 TABLERESULTS 选项一起使用。

 

  解决碎片问题 

一旦你确定表或索引有碎片问题,那么你有4个选择去解决那些问题: 

1. 删除并重建索引 

2. 使用DROP_EXISTING子句重建索引 

3. 执行DBCC DBREINDEX 

4. 执行DBCC INDEXDEFRAG 

 

尽管每一个技术都能达到你整理索引碎片的最终目的,但各有各的优缺点。 

删除并重建索引 

DROP INDEXCREATE INDEXALTER TABLE来删除并重建索引有些缺陷包括在删除重建期间索引会消失。在索引删除重建时,对于查询它不在可用,

查询性能也许会受到明显的影响,直到重建索引为止。另一个潜在的缺陷是当都请求索引的时候会引起阻塞,直到重建索引为止。通过其他的处理也能解决阻塞,就是索引被使用的时候不删除索引。另一个主要的缺陷是在用

DROP INDEXCREATE INDEX重建聚集索引时会引起非聚集索引重建两次。

删除聚集索引时非聚集索引的行指针会指向数据堆,聚集索引重建时非聚集索引的行指针又会指回聚集索引的行位置。 删除并重建索引的确有一个好处就是通过重新排序索引页,使索引页紧凑并删除不需要的索引页来完全重建索引。你也许需要考虑那些内部和外部碎片都很高的