如何快速检测和解决数据库的 SQL 服务器索引碎片?

How can I quickly detect and resolve SQL Server Index fragmentation for a database?

我遇到过这样一种情况,随着添加更多记录,我对许多 SQL 服务器数据库的 table 的数据库操作变得非常慢(单次插入到table 有 100 万条记录)。

我估计这可能是由于我的数据库中 table 上的索引碎片造成的,因为我有许多 table 使用(并且需要使用)uniqueidentifier 类型主键聚簇索引。

我如何评估是否是这种情况,如果存在任何碎片问题,我如何解决碎片问题(可能每个部署一次)?

我想要一个适用于 SQL Server 2005 及更高版本的解决方案(我专门使用 Azure 数据库 (12.0.2000.8) 中的 SQL 服务器)。

这是一个在 SQL Server 2005 及更高版本中工作的 SQL 查询解决方案,它将让您

1)先找到所有需要重建或重组的索引,减少碎片,然后

2) 将结果的前五列中的单个copy-paste添加到一个新的查询window(删除第header行),执行所有语句(rebuild/reorganize 个索引),这将解决数据库中所有表中当前的大部分碎片问题。

注意:如果您 运行 遇到权限错误,您可能需要确保您位于主架构中并且您的用户对数据库具有适当的权限。

我将此查询命名为:GetFragmentationOfIndexesAndFirst5ColumnsExecutedResolveFragmentation.sql

SELECT  
'alter index' as 'reindex_part1',
'[' + dbindexes.[name] + ']' as 'Index',
'on' as 'reindex_part2',
'[' + dbtables.[name] + ']' as 'Table',
CASE WHEN indexstats.avg_fragmentation_in_percent > 30
 THEN 'rebuild with (FILLFACTOR = 80)' ELSE 'reorganize' END as 'reindex_part3',
indexstats.avg_fragmentation_in_percent,
indexstats.page_count,
indexstats.alloc_unit_type_desc,
dbschemas.[name] as 'Schema'
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.database_id = DB_ID()
AND indexstats.avg_fragmentation_in_percent > 5
ORDER BY indexstats.avg_fragmentation_in_percent desc

我必须归功于我在理解和最终得出这个解决方案时使用的两个地方:

在数据库中查找碎片的初始方法: https://myadventuresincoding.wordpress.com/2013/05/27/sql-server-check-index-fragmentation-on-all-indexes-in-a-database/

如何解决数据库中的碎片(5%-30% 的碎片应该通过索引重组来解决,30% 以上的碎片应该通过索引重建来解决): http://www.passionforsql.com/how-to-check-index-fragmentation-in-sql-server/

编辑: 我在上面的查询中包含了 with (FILLFACTOR = 80) 部分,因为在我的例子中,大部分碎片索引都在 uniqueidentifier 列上,这应该不使用默认的 FILLFACTOR 0 (100%) 进行索引,因为以这种方式使用它们将不可避免地再次快速导致碎片化,因为由于 non-ordered uniqueidentifiers 的创建,插入将始终需要放在其他行之间。您当然可以更改粘贴的值以删除或更改适合您的 tables/indexes.

的参数

我还发现您需要在重建和重组索引后执行 EXEC sp_updatestats,这样统计信息就可以跟上索引的变化,而不必在以后的查询中逐步执行。

既然你已经知道了table疑似碎片,你可以使用下面的T-SQL语句来识别碎片。

获取数据库的数据库 ID:

select name , database_id 
from sys.databases
where name = 'Database_Name'

运行这些查询在table所属的数据库下。

获取对象ID table:

select * from sys.objects where name = 'Table_name'

求 table 中的碎片百分比:

select TableName=object_name(dm.object_id)
       ,IndexName=i.name
       ,IndexType=dm.index_type_desc
       ,[%Fragmented]=avg_fragmentation_in_percent   ,dm.fragment_count      ,dm.page_count      ,dm.avg_fragment_size_in_pages     
,dm.record_count     ,dm.avg_page_space_used_in_percent  from 
sys.dm_db_index_physical_stats(14,420770742,null,null,'SAMPLED') dm 
--Here 14 is the Database ID 
--And 420770742 is the Object ID of the table
join sys.indexes i on dm.object_id=i.object_id and
dm.index_id=i.index_id   order by avg_fragmentation_in_percent desc

如果索引的碎片超过 20%,那么我们可以尝试重建该索引:

ALTER INDEX Index_Name 
ON [Database_name].[Table_Name] REBUILD

OR - 重建 table

中的所有索引
ALTER INDEX ALL ON [Database_name].[Table_Name]
REBUILD WITH (FILLFACTOR = 80)

或 - 通过使用 DBCC DBREINDEX

DBCC DBREINDEX ('[Database_name].[ Table_Name]')

DBCC DBREINDEX ('[Database_name].[ Table _Name]', 
'Index_Name, 85)

如果碎片计数低于 20%,您可以取消索引重建或 ReOrg.. 而只是更新 Index/Table 的统计信息。

要 运行 使用 FULLSCAN 更新 table 上的统计数据:

UPDATE STATISTICS [Database_Name].[Table_Name] 
with FULLSCAN

更新索引的统计数据

UPDATE STATISTICS [Database_Name].[Table_Name] Index_Name
with FULLSCAN

为了让您更好地了解正在做的事情,我将每一个问题都作为单独的问题给出了。希望这有帮助

检查 table

上的碎片百分比
SELECT a.index_id, 
       NAME, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM   sys.Dm_db_index_physical_stats(Db_id('dbName'), Object_id('tableName'), 
       NULL, 
              NULL, NULL) AS a 
       INNER JOIN sys.indexes b 
               ON a.object_id = b.object_id 
                  AND a.index_id = b.index_id 

要修复碎片,请重建或重新组织 table

上的索引
ALTER INDEX ALL ON table_name REBUILD 

ALTER INDEX index_name ON table_name REBUILD 

-- 重组

ALTER INDEX ALL ON table_name REORGANIZE

ALTER INDEX index_name ON table_name REORGANIZE

DBCC DBREINDEX ('table_Name')

https://docs.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes