用于重建和重新索引碎片索引的脚本?

sav*_*tha 26 sql-server indexing fragmentation

当'avg_fragmentation_in_percent'超出某些限制时,是否可以提供用于重建和重新索引碎片索引的脚本(如果不使用游标,则更好)?

KM.*_*KM. 27

要重建使用:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REBUILD
Run Code Online (Sandbox Code Playgroud)

或重组使用:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REORGANIZE
Run Code Online (Sandbox Code Playgroud)

应该在较低(<30%)碎片处使用重组,但只有重建(对数据库较重)才会将碎片降低到0%.
有关详细信息,请参阅https://msdn.microsoft.com/en-us/library/ms189858.aspx


Kni*_*ins 19

两种解决方案:一种简单,一种更先进.

介绍

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

替换为您自己的值,如下所示:

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

解决方案1.索引

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

ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD
Run Code Online (Sandbox Code Playgroud)

在脱机模式下为表重建一个指定的索引

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD
Run Code Online (Sandbox Code Playgroud)

解决方案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]
Run Code Online (Sandbox Code Playgroud)

碎片5..30%

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

重新组织表的所有索引

ALTER INDEX ALL ON XXXMYTABLEXXX REORGANIZE
Run Code Online (Sandbox Code Playgroud)

重组表的一个指定索引

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REORGANIZE
Run Code Online (Sandbox Code Playgroud)

碎片30%+

如果碎片值为30%或更高,则值得重建然后在线模式下的索引.

在表模式下以联机模式重建所有索引

ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
Run Code Online (Sandbox Code Playgroud)

在联机模式下为表重建一个指定的索引

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
Run Code Online (Sandbox Code Playgroud)

  • 重组始终在线。REBUILD 具有仅在企业版中可用的在线选项 (2认同)

Ima*_*idi 11

这是我从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
Run Code Online (Sandbox Code Playgroud)


Jon*_*ica 6

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

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

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


mr *_*r R 5

查询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
Run Code Online (Sandbox Code Playgroud)

输出量

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
Run Code Online (Sandbox Code Playgroud)