第三步:如果有碎片发生,重新整理它
到了这里,如果你已经在表里创建了所有正确的索引,但是,你可能还没有获得所希望的良好的性能。什么原因呢?有一种可能是出现了索引碎片。
1、什么是索引碎片
索引碎片是这样一种情形:由于在表里大量的插入、修改、删除操作而使索引页分裂。如果索引有了高的碎片,有两种情况,一种情况是扫描索引需要花费很多的时间,另一种情况是在查询的时候索引根本不使用索引,都会导致性能降低。
有2种类型的碎片:
内部破碎:由于索引页里的数据插入或修改操作而发生,以数据作为稀疏矩阵的形式的分布而结束,这将导致数据页的增加,从而增加查询时间。
外部破碎:由于索引/数据页的数据插入或修改而发生,以页码分离和在文件系统里不连贯的新的索引页的分配而结束,数据库服务器不能利用预读操作的优点,因为:下一个相关联的数据页不临近,而且这些相关连的下面的页码可能在数据文件的任何地方。
2、如何知道索引破碎是否已经发生?
在数据库执行下面的SQL语句(下面的语句在SQL server 2005及以后的版本运行正常,以你的目标数据库的名字取代AdventureWorks’)
SELECT object_name(dt.object_id) Tablename,si.name
IndexName,dt.avg_fragmentation_in_percent AS
ExternalFragmentation,dt.avg_page_space_used_in_percent AS
InternalFragmentation
FROM
(
SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats (db_id('AdventureWorks'),null,null,null,'DETAILED'
)
WHERE index_id <> 0) AS dt INNER JOIN sys.indexes si ON si.object_id=dt.object_id
AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10
AND dt.avg_page_space_used_in_percent<75 ORDER BY avg_fragmentation_in_percent DESC
上面的查询显示的AdventureWorks’数据库的索引碎片信息如下:

分析上面的结果,你就能发现在哪里出现了索引碎片,应用下面的规则:
ExternalFragmentation 的值 > 10,预示对应的索引出现外部碎片。InternalFragmentation 的值 < 75,预示对应的索引出现内部碎片
3、怎样重新整理索引碎片
有2种方式:
索引重组:执行下面的命令:
ALTER INDEX ALL ON TableName RECOGNIZE
索引重建:
ALTER INDEX ALL ON TableName REBUILD WITH (FILLFACTOR=90,ONLINE=ON)
通过使用具体索引的名字代替ALL ,你能重组或重建单个的索引。你也可以使用数据库控制台来重建/重组索引

4、什么时候重组和重建索引?
当外部碎片的值在10-15 ,内部碎片的值在60-75,对于这样的索引,你应该重组索引。否则,你应该重建索引。
关于索引重建的一个重要的事情是:一旦在一个特定的表上重建索引,表就会被锁定(重组的时候不会发生)。所以,对于一个产品数据库的一个大的表,因为在一个大表上的索引重建往往需要花费数个小时,我们不希望这种锁定。幸运的是,在SQL2005有一个解决方法,你可以在重建一个表的索引的时候,把ONLINE选项的值设为ON ,这样会使重建索引和表上的数据事务同样进行。
四、结束语
在数据表里的所有适合创建索引的字段上创建索引,这是非常诱惑人的。但是如果你正在从事一个事务数据库工作,在每个字段上创建索引并不是每次都是需要的。事实上,在一个OLTP系统上创建大量的索引可能会降低数据库的性能。(因为当很多操作是更新操作的时候,更新数据意味着更新索引)
一个首要的规则建议如下:
如果你在从事一个事务性数据库 ,平均不要在一个表上创建超过5个索引,另外,如果你在从事数据仓库,平均最高可在一个表上创建10个索引。