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

时间:2017-04-28 15:22:14

标签: sql sql-server azure-sql-database database-indexes fragmentation

我遇到过这样一种情况,即我的SQL Server数据库表中的数据库操作变得非常慢,因为添加了更多记录(单个插入到包含100万条记录的表为5秒)。

我估计这可能是由于我的数据库中表的碎片索引,因为我有许多表使用(并且需要使用)主键聚簇索引的唯一标识符类型。

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

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

3 个答案:

答案 0 :(得分:5)

检查表格上的碎片百分比

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 

要修复碎片,请重建或重组表格上的索引

ALTER INDEX ALL ON table_name REBUILD 

OR

ALTER INDEX index_name ON table_name REBUILD 

- 重组

ALTER INDEX ALL ON table_name REORGANIZE

OR

ALTER INDEX index_name ON table_name REORGANIZE

OR

DBCC DBREINDEX ('table_Name')

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

答案 1 :(得分:3)

由于您已经知道怀疑存在碎片的表,因此可以使用以下T-SQL语句来识别碎片。

获取数据库的数据库ID:

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

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

获取表格的对象ID:

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

要在表格中查找碎片百分比:

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 - 重建表中的所有索引

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 ..而只是更新该索引/表的统计信息。

使用FULLSCAN在表上运行update statistics:

UPDATE STATISTICS [Database_Name].[Table_Name] 
with FULLSCAN

更新索引的统计信息

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

我已将这些内容作为单独的查询给您,以便更好地了解正在执行的操作。希望这有帮助

答案 2 :(得分:1)

这是一个SQL查询解决方案,适用于SQL Server 2005及更高版本,可以让你

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

2)将结果的前五列的单个复制粘贴到新的查询窗口(删除列标题行),执行将解决大部分结果的所有语句(重建/重新组织索引)数据库中所有表中的当前碎片问题。

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

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

with (FILLFACTOR = 80)

我必须相信我用于理解并最终实现此解决方案的两个地方:

在数据库中查找碎片的初始方法: 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/

编辑:我在上面的查询中包含了EXEC sp_updatestats部分,因为在我的情况下,大多数碎片索引都在uniqueidentifier列上,不应该使用默认FILLFACTOR为0(100%),因为以这种方式使用它将不可避免地再次快速导致碎片,因为由于无序创建uniqueidentifier,所以总是需要将插入放在其他行之间。您当然可以更改粘贴值以删除或更改适合您的表/索引的参数。

我还发现,在重建和重新组织索引之后,您将需要执行{{1}},以便统计信息可以赶上索引更改,而不必在将来的查询中逐步执行此操作。