【问题标题】:How can I quickly detect and resolve SQL Server Index fragmentation for a database?如何快速检测和解决数据库的 SQL Server 索引碎片?
【发布时间】:2017-09-26 18:42:39
【问题描述】:

我遇到过这样一种情况,即我对许多 SQL Server 数据库表的数据库操作变得非常缓慢,因为添加了更多记录(单次插入到具有 100 万条记录的表需要 5 秒)。

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

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

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

【问题讨论】:

  • @TheGameiswar 在我的情况下,每个表上都有一个触发器,在插入后更新记录的CreatedAt 列(由 Azure 移动服务服务器端库放置,用于离线同步能力)。该触发器使每个插入都成为一个插入,然后是一个更新。

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


【解决方案1】:

这是一个适用于 SQL Server 2005 及更高版本的 SQL 查询解决方案,它将让您

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

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

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

我将此查询命名为: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%),因为以这种方式使用它们将不可避免地再次快速导致碎片,因为由于唯一标识符的无序创建,插入总是需要放在其他行之间。您当然可以更改粘贴的值以删除或更改适合您的表/索引的参数。

我还发现,您可能希望在重建和重组索引后执行 EXEC sp_updatestats,以便统计信息可以跟上索引更改,而不必在以后的查询中增量地这样做。

【讨论】:

    【解决方案2】:

    由于您已经知道怀疑有分片的表,您可以使用下面的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 [Database_Name].[Table_Name] 
    with FULLSCAN
    

    更新索引的统计信息

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

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

    【讨论】:

      【解决方案3】:

      查看表的碎片百分比

      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 
      

      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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-28
        • 1970-01-01
        相关资源
        最近更新 更多