显示指定的表的数据和索引的碎片信息。
语法
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 } ]
}
]
参数
table_name | table_id | view_name | view_id
是要对其碎片信息进行检查的表或视图。如果未指定,则对当前数据库中的所有表和索引视图进行检查。若要获得表或视图 ID,请使用 OBJECT_ID 函数。
index_name | index_id
是要对其碎片信息进行检查的索引。如果未指定,则该语句对指定表或视图的基索引进行处理。若要获得索引 ID,请使用 sysindexes。
WITH
指定由 DBCC 语句所返回的信息类型选项。
FAST
指定是否要对索引执行快速扫描和输出最少信息。快速扫描不读取索引的叶或数据级页。
TABLERESULTS
将结果显示为带有附加信息的行集。
ALL_INDEXES
显示指定表和视图的所有索引的结果(即使指定特定的索引)。
ALL_LEVELS
只能与 TABLERESULTS 选项一起使用。不能与 FAST 选项一起使用。指定是否为所处理的每个索引的每个级别产生输出。如果未指定,将只对索引叶级或表数据级进行处理。
注释
当指定 index_id 时,DBCC SHOWCONTIG 语句将遍历指定索引的叶级上的页链。如果只指定 table_id,或者如果index_id 为 0,则对指定表的数据页进行扫描。
DBCC SHOWCONTIG 确定表是否高度碎片化。在对表进行数据修改(INSERT、UPDATE 和 DELETE 语句)的过程中会出现表碎片现象。由于这些修改通常并不在表的行中进行平均分布,所以每页的填满状态会随时间而改变。对于扫描部分或全部表的查询,这些表碎片会导致额外的页读取,这将防碍数据的并行扫描。
当索引的碎片非常多时,有两种减少碎片的方法:
- 除去并重新创建聚集索引。
重新创建聚集索引将对数据进行重新组织,其结果是使数据页填满。填满程度可以使用 FILLFACTOR 选项进行配置。这种方法的缺点是索引在除去/重新创建周期内为脱机状态,并且操作属原子级。如果中断索引创建,则不会重新创建该索引。
- 使用 DBCC INDEXDEFRAG 按逻辑顺序重新排序索引的叶级页。
DBCC INDEXDEFRAG 命令是联机操作,所以索引只有在该命令正在运行时才可用。而且可以在不丢失已完成工作的情况下中断该操作。这种方法的缺点是在重新组织数据方面没有聚集索引的除去/重新创建操作有效。
结果集中的"每页上的平均可用字节数"和"平均页密度(完整)"统计量指出索引页的饱满程度。"每页上的平均可用字节数"的数字应较小,而"平均页密度(完整)"的数字应较大。在指定 FILLFACTOR 选项的情况下除去和重新创建聚集索引可改善这些统计。另外,DBCC INDEXDEFRAG 命令在压缩索引时考虑其 FILLFACTOR,这将改善这些统计。
索引的碎片级可以两种方式确定:
- 比较"扩展盘区开关数"和"扫描扩展盘区数"的值。
注意:如果索引跨多个文件,这种确定碎片的方法不起作用。"扩展盘区开关数"的值应尽可能接近于"扫描扩展盘区数"的值。算出这一比率作为"扫描密度"的值,该值应尽可能高。通过前面讨论的减少碎片的任一种方法可改善该值。
- 理解"逻辑扫描碎片"和"扩展盘区扫描碎片"的值。
"逻辑扫描碎片"和"扩展盘区扫描碎片"(对于较小的扩展盘区)的值很好地表明了表的碎片级。这些值应尽可能接近零(但 0% 到 10% 的值也可接受)。需要注意的是,如果索引跨多个文件,则"扩展盘区扫描碎片"的值较大。两种减少碎片的方法都可用于减少这些值。
结果集
下表描述结果集内的信息。
统计 | 描述 |
---|---|
扫描页数 | 表或索引的页数。 |
扫描扩展盘区数 | 表或索引中的扩展盘区数。 |
扩展盘区开关数 | 遍历索引或表的页时,DBCC 语句从一个扩展盘区移动到其它扩展盘区的次数。 |
平均扩展盘区上的平均页数 | 页链中每个扩展盘区的页数。 |
扫描密度 [最佳值:实际值] | 最佳值是指在一切都连续地链接的情况下,扩展盘区更改的理想数目。实际值是指扩展盘区更改的实际次数。如果一切都连续,则扫描密度数为 100;如果小于 100,则存在碎片。扫描密度为百分比值。 |
逻辑扫描碎片 | 对索引的叶级页扫描所返回的无序页的百分比。该数与堆集和文本索引无关。无序页是指在 IAM 中所指示的下一页不同于由叶级页中的下一页指针所指向的页。 |
扩展盘区扫描碎片 | 无序扩展盘区在扫描索引叶级页中所占的百分比。该数与堆集无关。无序扩展盘区是指:含有索引的当前页的扩展盘区不是物理上的含有索引的前一页的扩展盘区后的下一个扩展盘区。 |
平均每页上的平均可用字节数 | 所扫描的页上的平均可用字节数。数字越大,页的填满程度越低。数字越小越好。该数还受行大小影响:行大小越大,数字就越大。 |
平均页密度(完整) | 平均页密度(为百分比)。该值考虑行大小,所以它是页的填满程度的更准确表示。百分比越大越好。 |
如果指定表 ID 和 FAST 选项,DBCC SHOWCONTIG 将返回仅包含以下列的结果集:
- 扫描页数
- 扩展盘区开关数
- 扫描密度 [最佳值:实际值]
- 逻辑扫描碎片
如果指定 TABLERESULTS,DBCC SHOWCONTIG 将返回在第一个表中描述的 8 列和以下的附加列。
- ExtentSwitches
- AverageFreeBytes
- AveragePageDensity
- ScanDensity
- BestCount
- ActualCount
- LogicalFragmentation
- ExtentFragmentation
统计 | 描述 |
---|---|
ObjectName | 处理的表或视图的名称。 |
ObjectId | 对象名 ID。 |
IndexName | 处理的索引名。堆集的 IndexName 为 NULL。 |
IndexId | 索引的 ID。堆集的 IndexId 为 0。 |
Level | 索引的级别。级别 0 是索引的叶(或数据)级。级别数随着沿树向上移动到索引根而增加。堆集的级别为 0。 |
Pages | 组成某个索引级或整个堆集的页数。 |
Rows | 某个索引级上的数据或索引记录数。对于堆集,这是整个堆集中的数据记录数。 |
MinimumRecordSize | 某个索引级或整个堆集中的最小记录大小。 |
MaximumRecordSize | 某个索引级或整个堆集中的最大记录大小。 |
AverageRecordSize | 某个索引级或整个堆集中的平均记录大小。 |
ForwardedRecords | 某个索引级或整个堆集中的转发记录数。 |
Extents | 某个索引级或整个堆集中的扩展盘区数。 |
指定 TABLERESULTS 和 FAST 时,DBCC SHOWCONTIG 将返回如下列。
- ObjectName
- ObjectId
- IndexName
- IndexId
- Pages
- ExtentSwitchs
- ScanDensity
- BestCount
- ActualCount
- LogicalFragmentation
权限
DBCC SHOWCONTIG 权限默认授予 sysadmin 固定服务器角色或 db_owner 和 db_ddladmin 固定数据库角色的成员以及表的所有者且不可转让。
示例
A. 显示表的碎片信息
下例显示带指定表名的表的碎片信息。
USE Northwind GO DBCC SHOWCONTIG (Employees) GO
B. 使用 OBJECT_ID 获得表 ID 和使用 sysindexes 获得索引 ID
下例使用 OBJECT_ID 和 sysindexes 获得 authors 表的 aunmind 索引的表 ID 和索引 ID。
USE pubs GO DECLARE @id int, @indid int SET @id = OBJECT_ID('authors') SELECT @indid = indid FROM sysindexes WHERE id = @id AND name = 'aunmind' DBCC SHOWCONTIG (@id, @indid) GO
C. 显示表的简略结果集
下例返回 pubs 数据库中 authors 表的简略结果集。
USE pubs DBCC SHOWCONTIG ('authors', 1) WITH FAST
D. 显示数据库中每个表上的每个索引的完整结果集
下例显示 pubs 数据库中每个表上的每个索引的完整表结果集。
USE pubs DBCC SHOWCONTIG WITH TABLERESULTS, ALL_INDEXES
E. 使用 DBCC SHOWCONTIG 和 DBCC INDEXDEFRAG 对数据库中的索引进行碎片整理
下例显示对数据库中碎片数量在声明的阈值之上的所有索引进行碎片整理的简单方法。
/*Perform a 'USE <database name>' to select the database in which to run the script.*/ -- Declare variables SET NOCOUNT ON DECLARE @tablename VARCHAR (128) DECLARE @execstr VARCHAR (255) DECLARE @objectid INT DECLARE @indexid INT DECLARE @frag DECIMAL DECLARE @maxfrag DECIMAL -- Decide on the maximum fragmentation to allow SELECT @maxfrag = 30.0 -- Declare cursor DECLARE tables CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' -- Create the table CREATE TABLE #fraglist ( ObjectName CHAR (255), ObjectId INT, IndexName CHAR (255), IndexId INT, Lvl INT, CountPages INT, CountRows INT, MinRecSize INT, MaxRecSize INT, AvgRecSize INT, ForRecCount INT, Extents INT, ExtentSwitches INT, AvgFreeBytes INT, AvgPageDensity INT, ScanDensity DECIMAL, BestCount INT, ActualCount INT, LogicalFrag DECIMAL, ExtentFrag DECIMAL) -- Open the cursor OPEN tables -- Loop through all the tables in the database FETCH NEXT FROM tables INTO @tablename WHILE @@FETCH_STATUS = 0 BEGIN -- Do the showcontig of all indexes of the table INSERT INTO #fraglist EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''') WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS') FETCH NEXT FROM tables INTO @tablename END -- Close and deallocate the cursor CLOSE tables DEALLOCATE tables -- Declare cursor for list of indexes to be defragged DECLARE indexes CURSOR FOR SELECT ObjectName, ObjectId, IndexId, LogicalFrag FROM #fraglist WHERE LogicalFrag >= @maxfrag AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0 -- Open the cursor OPEN indexes -- loop through the indexes FETCH NEXT FROM indexes INTO @tablename, @objectid, @indexid, @frag WHILE @@FETCH_STATUS = 0 BEGIN PRINT 'Executing DBCC INDEXDEFRAG (0, ' + RTRIM(@tablename) + ', ' + RTRIM(@indexid) + ') - fragmentation currently ' + RTRIM(CONVERT(varchar(15),@frag)) + '%' SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@objectid) + ', ' + RTRIM(@indexid) + ')' EXEC (@execstr) FETCH NEXT FROM indexes INTO @tablename, @objectid, @indexid, @frag END -- Close and deallocate the cursor CLOSE indexes DEALLOCATE indexes -- Delete the temporary table DROP TABLE #fraglist GO