【问题标题】:Script for rebuilding and reindexing the fragmented index?用于重建和重新索引碎片索引的脚本?
【发布时间】:2010-11-08 09:05:49
【问题描述】:

当'avg_fragmentation_in_percent'超过某些限制(如果不使用游标更好)时,任何人都可以提供重建和重新索引碎片索引的脚本吗?

【问题讨论】:

  • 为什么不呢?任何人都可以选择提出任何他们向 Wiki 提问的问题。它避免失去代表点。
  • @Savitha:哪一部分有问题?我不确定您将如何使用光标进行操作。您是否正在寻找一个脚本来检测百分比然后重建?您是否查看了手册中的选项?有哪些可用的语句?您是否必须确定索引详细信息?是否有 ALTER INDEX 语句?
  • @Jonathan Leffler,但这是一个很好的合法问题,几乎没有投票失败的风险。更少的人查看 wiki 和/或想要回答零分。

标签: sql-server indexing fragmentation


【解决方案1】:

查询 REBUILD/REORGANIZE 索引

  • 30%
  • 5%
  • 5%> 什么都不做

查询:

SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName, 
ind.name AS IndexName, indexstats.index_type_desc AS IndexType, 
indexstats.avg_fragmentation_in_percent,
'ALTER INDEX ' + QUOTENAME(ind.name)  + ' ON ' +QUOTENAME(object_name(ind.object_id)) + 
CASE    WHEN indexstats.avg_fragmentation_in_percent>30 THEN ' REBUILD ' 
        WHEN indexstats.avg_fragmentation_in_percent>=5 THEN 'REORGANIZE'
        ELSE NULL END as [SQLQuery]  -- if <5 not required, so no query needed
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats 
INNER JOIN sys.indexes ind ON ind.object_id = indexstats.object_id 
    AND ind.index_id = indexstats.index_id 
WHERE 
--indexstats.avg_fragmentation_in_percent , e.g. >10, you can specify any number in percent 
ind.Name is not null 
ORDER BY indexstats.avg_fragmentation_in_percent DESC

输出

TableName      IndexName            IndexType              avg_fragmentation_in_percent SQLQuery
--------------------------------------------------------------------------------------- ------------------------------------------------------
Table1         PK_Table1            CLUSTERED INDEX        75                           ALTER INDEX [PK_Table1] ON [Table1] REBUILD 
Table1         IX_Table1_col1_col2  NONCLUSTERED INDEX     66,6666666666667             ALTER INDEX [IX_Table1_col1_col2] ON [Table1] REBUILD 
Table2         IX_Table2_           NONCLUSTERED INDEX     10                           ALTER INDEX [IX_Table2_] ON [Table2] REORGANIZE
Table2         IX_Table2_           NONCLUSTERED INDEX     3                            NULL

【讨论】:

    【解决方案2】:

    在 2016 年和 2017 年,真正的答案是:使用 Ola Hallengren 的脚本:

    https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html

    在我们相互进化的这一点上,这是我们任何人都需要知道或烦恼的。

    【讨论】:

      【解决方案3】:

      两种解决方案:一种简单,一种更高级。

      简介

      根据问题的严重程度,您可以使用两种解决方案

      替换成自己的值,如下:

      • XXXMYINDEXXXX 替换为索引名称。
      • XXXMYTABLEXXX 替换为表的名称。
      • XXXDATABASENAMEXXX 替换为数据库名称。

      解决方案 1. 索引

      在离线模式下重建表的所有索引

      ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD
      

      在离线模式下为表重建一个指定索引

      ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD
      

      解决方案 2. 碎片化

      在经常添加和删除条目的表中,碎片化是一个问题。

      检查碎片百分比

      SELECT  
          ips.[index_id] ,
          idx.[name] ,
          ips.[avg_fragmentation_in_percent]
      FROM    
          sys.dm_db_index_physical_stats(DB_ID(N'XXXMYDATABASEXXX'), OBJECT_ID(N'XXXMYTABLEXXX'), NULL, NULL, NULL) AS [ips]
          INNER JOIN sys.indexes AS [idx] ON [ips].[object_id] = [idx].[object_id] AND [ips].[index_id] = [idx].[index_id]
      

      碎片化 5..30%

      如果碎片值大于 5%,但小于 30%,则值得重新组织索引。

      重新组织表的所有索引

      ALTER INDEX ALL ON XXXMYTABLEXXX REORGANIZE
      

      为表重新组织一个指定索引

      ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REORGANIZE
      

      碎片化 30%+

      如果碎片值为 30% 或更大,则值得在联机模式下重建索引。

      在线模式下为表重建所有索引

      ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
      

      在线模式下为表重建一个指定索引

      ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
      

      【讨论】:

      • REORGANIZE 方法似乎没有 WITH (ONLINE = ON)
      • REORGANIZE 始终在线。 REBUILD 具有仅在企业版中可用的 ONLINE 选项
      【解决方案4】:

      这是我从http://www.foliotek.com/devblog/sql-server-optimization-with-index-rebuilding 获取的修改后的脚本,我发现它在此处发布很有用。 虽然它使用游标,但我知道游标的主要问题是什么,但它可以轻松转换为无游标版本。

      文档齐全,您可以轻松通读并根据需要进行修改。

        IF OBJECT_ID('tempdb..#work_to_do') IS NOT NULL 
              DROP TABLE tempdb..#work_to_do
      
      BEGIN TRY
      --BEGIN TRAN
      
      use yourdbname
      
      -- Ensure a USE  statement has been executed first.
      
          SET NOCOUNT ON;
      
          DECLARE @objectid INT;
          DECLARE @indexid INT;
          DECLARE @partitioncount BIGINT;
          DECLARE @schemaname NVARCHAR(130);
          DECLARE @objectname NVARCHAR(130);
          DECLARE @indexname NVARCHAR(130);
          DECLARE @partitionnum BIGINT;
          DECLARE @partitions BIGINT;
          DECLARE @frag FLOAT;
          DECLARE @pagecount INT;
          DECLARE @command NVARCHAR(4000);
      
          DECLARE @page_count_minimum SMALLINT
          SET @page_count_minimum = 50
      
          DECLARE @fragmentation_minimum FLOAT
          SET @fragmentation_minimum = 30.0
      
      -- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
      -- and convert object and index IDs to names.
      
          SELECT  object_id AS objectid ,
                  index_id AS indexid ,
                  partition_number AS partitionnum ,
                  avg_fragmentation_in_percent AS frag ,
                  page_count AS page_count
          INTO    #work_to_do
          FROM    sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL,
                                                 'LIMITED')
          WHERE   avg_fragmentation_in_percent > @fragmentation_minimum
                  AND index_id > 0
                  AND page_count > @page_count_minimum;
      
      IF CURSOR_STATUS('global', 'partitions') >= -1
      BEGIN
       PRINT 'partitions CURSOR DELETED' ;
          CLOSE partitions
          DEALLOCATE partitions
      END
      -- Declare the cursor for the list of partitions to be processed.
          DECLARE partitions CURSOR LOCAL
          FOR
              SELECT  *
              FROM    #work_to_do;
      
      -- Open the cursor.
          OPEN partitions;
      
      -- Loop through the partitions.
          WHILE ( 1 = 1 )
              BEGIN;
                  FETCH NEXT
      FROM partitions
      INTO @objectid, @indexid, @partitionnum, @frag, @pagecount;
      
                  IF @@FETCH_STATUS < 0
                      BREAK;
      
                  SELECT  @objectname = QUOTENAME(o.name) ,
                          @schemaname = QUOTENAME(s.name)
                  FROM    sys.objects AS o
                          JOIN sys.schemas AS s ON s.schema_id = o.schema_id
                  WHERE   o.object_id = @objectid;
      
                  SELECT  @indexname = QUOTENAME(name)
                  FROM    sys.indexes
                  WHERE   object_id = @objectid
                          AND index_id = @indexid;
      
                  SELECT  @partitioncount = COUNT(*)
                  FROM    sys.partitions
                  WHERE   object_id = @objectid
                          AND index_id = @indexid;
      
                  SET @command = N'ALTER INDEX ' + @indexname + N' ON '
                      + @schemaname + N'.' + @objectname + N' REBUILD';
      
                  IF @partitioncount > 1
                      SET @command = @command + N' PARTITION='
                          + CAST(@partitionnum AS NVARCHAR(10));
      
                  EXEC (@command);
                  --print (@command); //uncomment for testing
      
                  PRINT N'Rebuilding index ' + @indexname + ' on table '
                      + @objectname;
                  PRINT N'  Fragmentation: ' + CAST(@frag AS VARCHAR(15));
                  PRINT N'  Page Count:    ' + CAST(@pagecount AS VARCHAR(15));
                  PRINT N' ';
              END;
      
      -- Close and deallocate the cursor.
          CLOSE partitions;
          DEALLOCATE partitions;
      
      -- Drop the temporary table.
          DROP TABLE #work_to_do;
      --COMMIT TRAN
      
      END TRY
      BEGIN CATCH
      --ROLLBACK TRAN
          PRINT 'ERROR ENCOUNTERED:' + ERROR_MESSAGE()
      END CATCH
      

      【讨论】:

      • 刚看到这个...感谢您的肯定!
      【解决方案5】:

      重建使用:

      ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REBUILD
      

      或重新组织使用:

      ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REORGANIZE
      

      重组应该用于较低 ( 欲了解更多信息,请参阅https://msdn.microsoft.com/en-us/library/ms189858.aspx

      【讨论】:

        【解决方案6】:

        我发现以下脚本非常擅长维护索引,您可以将其安排为每晚运行或您希望的任何其他时间范围。

        http://sqlfool.com/2011/06/index-defrag-script-v4-1/

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多