Frage

In den SSW-Regeln zur Verbesserung der SQL Server-Datenbank finden Sie ein Beispiel für einen vollständigen Datenbankwartungsplan: SSW.Im Beispiel führen sie sowohl einen „Index neu organisieren“ als auch einen „Index neu erstellen“ und anschließend „Statistiken aktualisieren“ aus.Hat das irgendeinen Sinn?Ich dachte, Reorganize Index sei eine schnelle, aber weniger effektive Version von Rebuild Index?und dass eine Indexneuerstellung auch die Statistiken automatisch aktualisieren würde (zumindest für den Clustered-Index).

War es hilfreich?

Lösung

Mache ein REORGANIZE und dann a REBUILD auf denselben Indizes ist sinnlos, da alle Änderungen durch die REORGANIZE würde dadurch verloren gehen REBUILD.

Schlimmer noch ist, dass im Wartungsplandiagramm von SSW ein Fehler auftritt SHRINK Erstens fragmentiert es die Indizes als Nebeneffekt der Art und Weise, wie es Speicherplatz freigibt.Dann ist die REBUILD Weist den Datenbankdateien während des Vorgangs wieder mehr Speicherplatz als Arbeitsspeicher zu REBUILD Betrieb.

  • REORGANIZE ist ein Online-Vorgang, der Blattseiten in einem gruppierten oder nicht gruppierten Index Seite für Seite defragmentiert und nur wenig zusätzlichen Arbeitsraum beansprucht.

  • REBUILD ist in den Enterprise-Editionen ein Online-Vorgang, in anderen Editionen ein Offline-Vorgang und benötigt wieder so viel zusätzlichen Arbeitsraum wie die Indexgröße.Es erstellt eine neue Kopie des Index und löscht dann die alte, wodurch die Fragmentierung beseitigt wird.Statistiken werden im Rahmen dieses Vorgangs standardmäßig neu berechnet, dies kann jedoch deaktiviert werden.

Sehen Reorganisation und Neuaufbau von Indizes für mehr Informationen.

Nicht verwenden SHRINK außer mit dem TRUNCATEONLY Option und selbst dann, wenn die Datei wieder wächst, sollten Sie genau überlegen, ob es notwendig ist:

sqlservercentral_SHRINKFILE

Andere Tipps

Reorganisation und Neuaufbau sind verschiedene Dinge.

Reorganisieren:Es ist eine Defragmentierung für Indizes.Übernimmt die vorhandenen Indizes und defragmentiert die vorhandenen Seiten.Wenn die Seiten jedoch nicht zusammenhängend sind, bleiben sie wie zuvor.Lediglich der Inhalt der Seiten ändert sich.

Neuaufbau:Tatsächlich wird der Index gelöscht und von Grund auf neu erstellt.Das bedeutet, dass Sie einen völlig neuen Index mit defragmentierten und zusammenhängenden Seiten erhalten.

Darüber hinaus können Sie mit Rebuild die Partitionierung oder Dateigruppen ändern, mit Reorganize können Sie jedoch nicht nur den gesamten Index, sondern auch nur eine Partition des Index defragmentieren.

Die Aktualisierungsstatistik erfolgt bei Clustered-Indizes automatisch, bei Nicht-Cluster-Indizes jedoch nicht.

Bevor Sie über die Pflege von Indizes nachdenken, ist es wichtig, zwei Hauptfragen zu beantworten:

  1. Wie hoch ist der Fragmentierungsgrad?
  2. Was ist die angemessene Maßnahme?Reorganisieren oder neu aufbauen?

Wie in diesem Artikel beschrieben http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/, Um Ihnen bei der Entscheidung zu helfen, ob Sie einen Indexneuaufbau oder eine Indexreorganisation durchführen sollten, beachten Sie bitte Folgendes:

  • Bei der Indexreorganisation handelt es sich um einen Prozess, bei dem der SQL Server den vorhandenen Index durchgeht und ihn bereinigt.Die Indexneuerstellung ist ein aufwändiger Prozess, bei dem der Index gelöscht und dann von Grund auf mit einer völlig neuen Struktur neu erstellt wird, frei von allen angehäuften Fragmenten und leeren Seiten.

  • Während es sich bei der Indexreorganisation um einen reinen Bereinigungsvorgang handelt, bei dem der Systemstatus unverändert bleibt, ohne dass betroffene Tabellen und Ansichten gesperrt werden, sperrt der Neuerstellungsprozess die betroffene Tabelle für den gesamten Neuerstellungszeitraum, was zu langen Ausfallzeiten führen kann, die nicht akzeptabel sind einige Umgebungen.Vor diesem Hintergrund ist es klar, dass die Indexneuerstellung ein Prozess mit einer „stärkeren“ Lösung ist, der jedoch seinen Preis hat – möglicherweise lange Sperren für betroffene indizierte Tabellen.

Auf der anderen Seite ist die Indexreorganisation ein „leichter“ Prozess, der die Fragmentierung auf weniger effektive Weise löst – da der bereinigte Index immer an zweiter Stelle steht gegenüber dem neuen, vollständig von Grund auf neu erstellten Index.Unter dem Gesichtspunkt der Effizienz ist die Neuorganisation des Index jedoch viel besser, da dadurch die betroffene indizierte Tabelle während des Betriebs nicht gesperrt wird.

Im oben genannten Artikel wird auch erläutert, wie Sie Indizes mithilfe von SSMS, T-SQL (um Indizes in einer Tabelle neu zu organisieren/neu zu erstellen) und einem Drittanbieter-Tool namens ApexSQL Backup neu organisieren und erstellen.

Wenn bei der Neuorganisation eines Index der Index auf zwei oder mehr physische Dateien verteilt ist, werden die Daten nur innerhalb der Datendatei defragmentiert.Seiten werden nicht von einer Datendatei in eine andere verschoben.

Wenn sich der Index in einer einzelnen Datei befindet, führen die Neuorganisation und die Neuindizierung zum gleichen Endergebnis.

Manchmal ist die Neuorganisation schneller und manchmal ist die Neuindizierung schneller, je nachdem, wie fragmentiert der Index ist.Je weniger fragmentiert der Index ist, desto schneller ist eine Neuorganisation. Je stärker fragmentiert, desto langsamer ist die Neuorganisation, aber desto schneller ist eine Neuindizierung.

Genau was Biri sagte.So würde ich eine gesamte Datenbank neu indizieren:

EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"

Ich verwende diesen SP

CREATE PROCEDURE dbo.[IndexRebuild]
AS 
DECLARE @TableName NVARCHAR(500);
DECLARE @SQLIndex NVARCHAR(MAX);
DECLARE @RowCount INT;
DECLARE @Counter INT;

DECLARE @IndexAnalysis TABLE
    (
      AnalysisID INT IDENTITY(1, 1)
                     NOT NULL
                     PRIMARY KEY ,
      TableName NVARCHAR(500) ,
      SQLText NVARCHAR(MAX) ,
      IndexDepth INT ,
      AvgFragmentationInPercent FLOAT ,
      FragmentCount BIGINT ,
      AvgFragmentSizeInPages FLOAT ,
      PageCount BIGINT
    )

BEGIN
    INSERT  INTO @IndexAnalysis
            SELECT  [objects].name ,
                    'ALTER INDEX [' + [indexes].name + '] ON ['
                    + [schemas].name + '].[' + [objects].name + '] '
                    + ( CASE WHEN (   [dm_db_index_physical_stats].avg_fragmentation_in_percent >= 20
                                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent < 40
                                  ) THEN 'REORGANIZE'
                             WHEN [dm_db_index_physical_stats].avg_fragmentation_in_percent > = 40
                             THEN 'REBUILD'
                        END ) AS zSQL ,
                    [dm_db_index_physical_stats].index_depth ,
                    [dm_db_index_physical_stats].avg_fragmentation_in_percent ,
                    [dm_db_index_physical_stats].fragment_count ,
                    [dm_db_index_physical_stats].avg_fragment_size_in_pages ,
                    [dm_db_index_physical_stats].page_count
            FROM    [sys].[dm_db_index_physical_stats](DB_ID(), NULL, NULL,
                                                       NULL, 'LIMITED') AS   [dm_db_index_physical_stats]
                    INNER JOIN [sys].[objects] AS [objects] ON (   [dm_db_index_physical_stats].[object_id] = [objects].[object_id] )
                    INNER JOIN [sys].[schemas] AS [schemas] ON ( [objects].[schema_id]  = [schemas].[schema_id] )
                    INNER JOIN [sys].[indexes] AS [indexes] ON (  [dm_db_index_physical_stats].[object_id] = [indexes].[object_id]
                                                          AND  [dm_db_index_physical_stats].index_id = [indexes].index_id
                                                          )
            WHERE   index_type_desc <> 'HEAP'
                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent > 20
END

SELECT  @RowCount = COUNT(AnalysisID)
FROM    @IndexAnalysis

SET @Counter = 1
WHILE @Counter <= @RowCount 
    BEGIN

        SELECT  @SQLIndex = SQLText
        FROM    @IndexAnalysis
        WHERE   AnalysisID = @Counter

        EXECUTE sp_executesql @SQLIndex

        SET @Counter = @Counter + 1

    END
 GO

und erstellen Sie einen Job, der diesen SP jede Woche ausführt.

Noch besser ist:

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX'

oder

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE'

Meine zwei Cent...Diese Methode folgt der auf Tech Net beschriebenen Spezifikation: http://technet.microsoft.com/en-us/library/ms189858(v=sql.105).aspx

USE [MyDbName]
GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [maintenance].[IndexFragmentationCleanup]
AS
DECLARE @reIndexRequest VARCHAR(1000)

DECLARE reIndexList CURSOR
FOR
SELECT INDEX_PROCESS
FROM (
    SELECT CASE 
            WHEN avg_fragmentation_in_percent BETWEEN 5
                    AND 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REORGANIZE;'
            WHEN avg_fragmentation_in_percent > 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REBUILD with(ONLINE=ON);'
            END AS INDEX_PROCESS
        ,avg_fragmentation_in_percent
        ,t.NAME
    FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) AS a
    INNER JOIN sys.indexes AS i ON a.object_id = i.object_id
        AND a.index_id = i.index_id
    INNER JOIN sys.tables t ON t.object_id = i.object_id
    WHERE i.NAME IS NOT NULL
    ) PROCESS
WHERE PROCESS.INDEX_PROCESS IS NOT NULL
ORDER BY avg_fragmentation_in_percent DESC

OPEN reIndexList

FETCH NEXT
FROM reIndexList
INTO @reIndexRequest

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY

        PRINT @reIndexRequest;

        EXEC (@reIndexRequest);

    END TRY

    BEGIN CATCH
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = 'UNABLE TO CLEAN UP INDEX WITH: ' + @reIndexRequest + ': MESSAGE GIVEN: ' + ERROR_MESSAGE()
            ,@ErrorSeverity = 9 
            ,@ErrorState = ERROR_STATE();

    END CATCH;

    FETCH NEXT
    FROM reIndexList
    INTO @reIndexRequest
END

CLOSE reIndexList;

DEALLOCATE reIndexList;

RETURN 0

GO

Ich habe im Internet recherchiert und einige gute Artikel gefunden.Am und habe ich die Funktion und das Skript unten geschrieben, die alle Indizes in einer Datenbank neu organisieren, neu erstellen oder neu erstellen.

Zuerst müssen Sie möglicherweise lesen Dieser Artikel um zu verstehen, warum wir nicht einfach alle Indizes neu erstellen.

Zweitens benötigen wir eine Funktion zum Erstellen eines Skripts für den Index.Also Dieser Artikel kann helfen.Außerdem teile ich unten die Arbeitsfunktion.

Im letzten Schritt wird eine While-Schleife erstellt, um alle Indizes in der Datenbank zu finden und zu organisieren. Dieses Video ist ein tolles Beispiel dafür.

Funktion:

create function GetIndexCreateScript(
    @index_name nvarchar(100)
) 
returns nvarchar(max)
as
begin

declare @Return   varchar(max)

SELECT @Return = ' CREATE ' + 
    CASE WHEN I.is_unique = 1 THEN ' UNIQUE ' ELSE '' END  +  
    I.type_desc COLLATE DATABASE_DEFAULT +' INDEX ' +   
    I.name  + ' ON '  +  
    Schema_name(T.Schema_id)+'.'+T.name + ' ( ' + 
    KeyColumns + ' )  ' + 
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') + 
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( ' + 
    CASE WHEN I.is_padded = 1 THEN ' PAD_INDEX = ON ' ELSE ' PAD_INDEX = OFF ' END + ','  + 
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  + 
    -- default value 
    'SORT_IN_TEMPDB = OFF '  + ','  + 
    CASE WHEN I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON ' ELSE ' IGNORE_DUP_KEY = OFF ' END + ','  + 
    CASE WHEN ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF ' ELSE ' STATISTICS_NORECOMPUTE = ON ' END + ','  + 
    -- default value  
    ' DROP_EXISTING = ON '  + ','  + 
    -- default value  
    ' ONLINE = OFF '  + ','  + 
   CASE WHEN I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON ' ELSE ' ALLOW_ROW_LOCKS = OFF ' END + ','  + 
   CASE WHEN I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON ' ELSE ' ALLOW_PAGE_LOCKS = OFF ' END  + ' ) ON [' + 
   DS.name + ' ] '  
FROM sys.indexes I   
 JOIN sys.tables T ON T.Object_id = I.Object_id    
 JOIN sys.sysindexes SI ON I.Object_id = SI.id AND I.index_id = SI.indid   
 JOIN (SELECT * FROM (  
    SELECT IC2.object_id , IC2.index_id ,  
        STUFF((SELECT ' , ' + C.name + CASE WHEN MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN ' DESC ' ELSE ' ASC ' END 
    FROM sys.index_columns IC1  
    JOIN Sys.columns C   
       ON C.object_id = IC1.object_id   
       AND C.column_id = IC1.column_id   
       AND IC1.is_included_column = 0  
    WHERE IC1.object_id = IC2.object_id   
       AND IC1.index_id = IC2.index_id   
    GROUP BY IC1.object_id,C.name,index_id  
    ORDER BY MAX(IC1.key_ordinal)  
       FOR XML PATH('')), 1, 2, '') KeyColumns   
    FROM sys.index_columns IC2   
    --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables  
    GROUP BY IC2.object_id ,IC2.index_id) tmp3 )tmp4   
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id  
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id   
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id   
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id   
 LEFT JOIN (SELECT * FROM (   
    SELECT IC2.object_id , IC2.index_id ,   
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1   
    JOIN Sys.columns C    
       ON C.object_id = IC1.object_id    
       AND C.column_id = IC1.column_id    
       AND IC1.is_included_column = 1   
    WHERE IC1.object_id = IC2.object_id    
       AND IC1.index_id = IC2.index_id    
    GROUP BY IC1.object_id,C.name,index_id   
       FOR XML PATH('')), 1, 2, '') IncludedColumns    
   FROM sys.index_columns IC2    
   --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables   
   GROUP BY IC2.object_id ,IC2.index_id) tmp1   
   WHERE IncludedColumns IS NOT NULL ) tmp2    
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id   
WHERE I.is_primary_key = 0 AND I.is_unique_constraint = 0 
AND I.[name] = @index_name

return @Return

end

SQL für eine Weile:

declare @RebuildIndex Table(
    IndexId int identity(1,1),
    IndexName varchar(100),
    TableSchema varchar(50),
    TableName varchar(100),
    Fragmentation decimal(18,2)
)


insert into @RebuildIndex (IndexName,TableSchema,TableName,Fragmentation)
SELECT 
    B.[name] as 'IndexName', 
    Schema_Name(O.[schema_id]) as 'TableSchema',
    OBJECT_NAME(A.[object_id]) as 'TableName',
    A.[avg_fragmentation_in_percent] Fragmentation
FROM sys.dm_db_index_physical_stats(db_id(),NULL,NULL,NULL,'LIMITED') A 
INNER JOIN sys.indexes B ON A.[object_id] = B.[object_id] and A.index_id = B.index_id  
INNER JOIN sys.objects O ON O.[object_id] = B.[object_id]  
 where B.[name] is not null and B.is_primary_key = 0 AND B.is_unique_constraint = 0 and A.[avg_fragmentation_in_percent] >= 5  

--select * from @RebuildIndex

 declare @begin int = 1
 declare @max int
 select @max = Max(IndexId) from @RebuildIndex
 declare @IndexName varchar(100), @TableSchema varchar(50), @TableName varchar(100) , @Fragmentation decimal(18,2)

 while @begin <= @max
 begin

    Select @IndexName = IndexName from @RebuildIndex where IndexId = @begin
    select @TableSchema = TableSchema  from @RebuildIndex where IndexId = @begin
    select @TableName = TableName  from @RebuildIndex where IndexId = @begin 
    select @Fragmentation = Fragmentation  from @RebuildIndex where IndexId = @begin 

    declare @sql nvarchar(max)
    if @Fragmentation < 31
    begin
        set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REORGANIZE WITH ( LOB_COMPACTION = ON )'
        print 'Reorganized Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
    end
    else
    begin
        set @sql = (select dbo.GetIndexCreateScript(@IndexName))
        if(@sql is not null)
        begin
            print 'Recreated Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end 
        else
        begin
            set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REBUILD PARTITION = ALL WITH (ONLINE = ON)'
            print 'Rebuilded Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end
    end

    execute(@sql)


    set @begin = @begin+1

end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top