索引碎片小结

在SQL Server数据库,当索引碎片较多时,会拖慢查询的速度,进而影响SQL查询的性能,这时可以通过DBCC ShowContig或DBCC ShowContig(表名)检查索引碎片情况,指导我们对其进行定时重建整理。本文我们就介绍这一过程,接下来我们就来一起了解一下吧。
  执行DBCC ShowContig后的运行结果如下:

DBCC SHOWCONTIG 正在扫描 'tbModule' 表...
表: 'tbModule' (52195236);索引 ID: 0,数据库 ID: 13
已执行 TABLE 级别的扫描。
- 扫描页数................................: 904501
- 扫描区数..............................: 113076
- 区切换次数..............................: 113075
- 每个区的平均页数........................: 8.0
- 扫描密度 [最佳计数:实际计数].......: 99.99% [113063:113076]
- 区扫描碎片 ..................: 34.14%
- 每页的平均可用字节数.....................: 146.6
- 平均页密度(满).....................: 98.19%
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

  相关解释如下:

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

  Extents Scanned-扫描扩展盘区数:用扫描页数除以8,四舍五入到下一个最高值。该值应该和DBCC SHOWCONTIG返回的扫描扩展盘区数一致。如果DBCC SHOWCONTIG返回的数高,说明存在外部碎片。碎片的严重程度依赖于刚才显示的值比估计值高多少。

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

  Avg. Pages per Extent-每个扩展盘区上的平均页数:该数是扫描页数除以扫描扩展盘区数,一般是8。小于8说明有外部碎片。

  Scan Density [Best Count:Actual Count]-扫描密度[最佳值:实际值]:DBCC SHOWCONTIG返回最有用的一个百分比。这是扩展盘区的最佳值和实际值的比率。该百分比应该尽可能靠近100%。低了则说明有外部碎片。

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

  Extent Scan Fragmentation-扩展盘区扫描碎片:无序扩展盘区在扫描索引叶级页中所占的百分比。该百分比应该是0%,高了则说明有外部碎片。

  Avg. Bytes Free per Page-每页上的平均可用字节数:所扫描的页上的平均可用字节数。越高说明有内部碎片,不过在你用这个数字决定是否有内部碎片之前,应该考虑fill factor(填充因子)。

  Avg. Page Density (full)-平均页密度(完整):每页上的平均可用字节数的百分比的相反数。低的百分比说明有内部碎片。

  通过对扫描密度(过低),扫描碎片(过高)的结果分析,判定是否需要索引重建。

  处理方式:一是利用DBCC INDEXDEFRAG整理索引碎片,二是利用DBCC DBREINDEX重建索引。二者各有优缺点。

  调用微软的原话如下:

  DBCC INDEXDEFRAG 命令是联机操作,所以索引只有在该命令正在运行时才可用,而且可以在不丢失已完成工作的情况下中断该操作。这种方法的缺点是在重新组织数据方面没有聚集索引的除去/重新创建操作有效。

  DBCC DBREINDEX 重新创建聚集索引将对数据进行重新组织,其结果是使数据页填满。填满程度可以使用 FILLFACTOR 选项进行配置。这种方法的缺点是索引在除去/重新创建周期内为脱机状态,并且操作属原子级。如果中断索引创建,则不会重新创建该索引。也就是说,要想获得好的效果,还是得用重建索引,所以决定重建索引。  
DBCC INDEXDEFRAG 每隔 5 分钟向用户报告预计完成的百分比。可在进程中的任一点结束 DBCC INDEXDEFRAG,任何已完成的工作都将保留。
与 DBCC DBREINDEX(一般的索引生成操作)不同,DBCC INDEXDEFRAG 是联机操作。它不长期控制锁,因此不会防碍运行查询或更新。若索引的碎片相对较少,则整理该索引的速度比生成一个新索引要快,这是因为碎片整理所需的时间与碎片的数量有关。对碎片太多的索引进行整理可能要比重建花更多的时间。另外,始终对碎片整理进行完整的日志记录,与数据库恢复模型设置无关(请参见 ALTER DATABASE)。对碎片太多的索引进行整理所生成的日志记录可能比完全记录的索引创建还要多。然而,若需经常进行日志备份或如果恢复模型设置是 SIMPLE,碎片整理将作为一系列短事务执行,因此不需要大量的日志。
另外,如果两个索引在磁盘上交叉存取事务,DBCC INDEXDEFRAG 将没有作用,原因是 INDEXDEFRAG 打乱了已有的页。若要改善页的聚集,请重建索引。
不支持在系统表上使用 DBCC INDEXDEFRAG。
语法: DBCC INDEXDEFRAG (库,表,索引名)

DBCC INDEXDEFRAG
( { database_name | database_id | 0 }
, { table_name | table_id | 'view_name' | view_id }
, { index_name | index_id }
) [ WITH NO_INFOMSGS ]

结果集如果没有指定 WITH NO_INFOMSGS,DBCC INDEXDEFRAG 将返回以下结果集(值可能会有变化):

Pages Scanned Pages Moved Pages Removed
------------- ----------- -------------
359 346 8
(1 row(s) affected)

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

权限
DBCC INDEXDEFRAG 权限默认授予 sysadmin 固定服务器角色或 db_owner 和 db_ddladmin 固定数据库角色的成员以及表的所有者且不可转让。
示例

DBCC INDEXDEFRAG (Northwind, Orders, CustomersOrders)
GO

重建索引 DBCC DBREINDEX 是一个脱机操作。 如果重新生成了非聚集索引,则在该操作的持续时间内,相关表持有共享锁。 这可以禁止对表进行修改。 如果重新生成了聚集索引,则持有排他表锁。 这可以禁止任何表访问,因此可以有效地使表脱机。重新生成表的一个索引或为表定义的所有索引。 通过允许动态重新生成索引,可以重新生成强制 PRIMARY KEY 或 UNIQUE 约束的索引,而不必删除并重新创建这些约束。 这意味着无需了解表的结构或其约束,即可重新生成索引。
语法:  DBCC DBREINDEX(表,索引名,填充因子)

DBCC DBREINDEX 
( 
table_name 
[ , index_name [ , fillfactor ] ] 
) 
[ WITH NO_INFOMSGS ] 

  第一个参数,可以是表名,也可以是表ID。

  第二个参数,如果是'',表示影响该表的所有索引。

  第三个参数,填充因子,即索引页的数据填充程度。如果是100,表示每一个索引页都全部填满,此时select效率最高,但以后要插入索引时,就得移动后面的所有页,效率很低。如果是0,表示使用先前的填充因子值。

  如对表tbModule的所有索引进行重建,填充因子比例为80% ,可以这么写:DBCC DBREINDEX(tbModule,'',80)。
例子:
以下示例使用填充因子值 70 对 AdventureWorks 中的 Employee 表重新生成所有索引。

USE AdventureWorks2012; 
GO 
DBCC DBREINDEX ('HumanResources.Employee', ' ', 70); 
GO 
 

 另一种直观查看方式:

--如何知道是否发生了索引碎片

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('DB_DJSMS'),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

索引碎片信息

--使用下面的规则分析结果 你就可以找出哪里发生了索引碎片

--1)ExternalFragmentation的值>10表示对应的索引发生了外部碎片;

--2)InternalFragmentation的值<75表示对应的索引发生了内部碎片

如何整理索引碎片:

1)重组有碎片的索引执行下面的命令

ALTER INDEX ALL ON TableName REORGANIZE

2)重建索引执行下面的命令

ALTER INDEX ALL ON TableName REBUILD WITH (FILLFACTOR=90,ONLINE=ON)

--也可以使用索引名代替这里的ALL关键字重组或重建单个索引 也可以使用SQL Server管理工作台进行索引碎片的整理

注意:

使用SQL Server管理工作台整理索引碎片

什么时候用重组什么时候用重建呢?

当对应索引的外部碎片值介于10-15之间内部碎片值介于60-75之间时使用重组其它情况就应该使用重建

值得注意的是重建索引时索引对应的表会被锁定但重组不会锁表因此在生产系统中对大表重建索引要慎重因为在大表上创建索引可能会花几个小时
幸运的是从SQL Server 2005开始微软提出了一个解决办法在重建索引时将ONLINE选项设置为ON这样可以保证重建索引时表仍然可以正常使用

虽然索引可以提高查询速度但如果你的数据库是一个事务型数据库大多数时候都是更新操作更新数据也就意味着要更新索引
这个时候就要兼顾查询和更新操作了因为在OLTP数据库表上创建过多的索引会降低整体数据库性能

如果你的数据库是事务型的平均每个表上不能超过5个索引 如果你的数据库是数据仓库型平均每个表可以创建10个索引都没问题
原文地址:https://www.cnblogs.com/lx823706/p/5682017.html