REORGANIZE scheint die ganze Zeit genauso gut zu funktionieren wie REBUILD

7

Auf dieser MSDN-Seite steht, ob Sie basierend auf dem Grad der Fragmentierung neu organisieren oder neu erstellen sollten:

 5% bis 30% -> ALTER INDEX REORGANIZE  
 Über 30% -> ALTER INDEX REBUILD WITH (ONLINE = ON) *

Wir haben jedoch festgestellt, dass REORGANIZE auch bei einer sehr hohen Fragmentierung (über 95%) auf großen und kleinen Tabellen einwandfrei funktioniert. (Die Fragmentierung sinkt auf weniger als 1%).

Warum sagt die MSDN-Seite das? Soll es nicht so funktionieren wie bei mir?

Oder gibt es einen Nachteil, den ich vermisse? (Ein verstecktes Problem, wenn ich nicht neu aufbaue?)

Vaccano
quelle

Antworten:

9

Lassen Sie mich einen anderen Teil derselben Seite zitieren, auf dem im Grunde IT DEPENDS steht - Hervorhebung von mir:

Diese Werte bieten eine grobe Richtlinie für die Bestimmung des Punkts, an dem Sie zwischen ALTER INDEX REORGANIZE und ALTER INDEX REBUILD wechseln sollten. Die tatsächlichen Werte können jedoch von Fall zu Fall variieren . Es ist wichtig, dass Sie experimentieren, um den besten Schwellenwert für Ihre Umgebung zu ermitteln .

Es gibt keine wirklich gute Antwort darauf, außer "es kommt darauf an" ... dies sind nur allgemeine Richtlinien und können abhängig von der Anzahl der Zeilen, den Spalten in Ihrem Index, ihren Datentypen und der Breite des Index angemessen sein oder auch nicht , was sonst wird zwischen den Schreibvorgängen in diese Tabellen usw. auf die Festplatte geschrieben?

Wie groß sollte ich Tempdb sein, was ist ein guter Schwellenwert für PLE und welche Art von Auto sollte ich kaufen, die Antwort ist dieselbe: ES HÄNGT AB .

Aaron Bertrand
quelle
Wenn es nicht funktionieren würde, würde es die Fragmentierung nicht verringern? (IE: Solange die Fragmentierung
sinkt,
@Vaccano Einige würden sagen, dass Sie sich sowieso keine Sorgen um Fragmentierung machen müssen. Siehe diesen Artikel und diesen Artikel . Ich schlage nicht vor, dass Sie es ignorieren sollten, aber es scheint, dass Sie mehr darüber nachdenken, als Sie brauchen. Haben Sie tatsächliche Hinweise auf tatsächliche Leistungsprobleme, wenn der Index stark fragmentiert ist? Und dass diese Probleme verschwinden, sobald Sie sie "behoben" haben? Halten Sie jeden Morgen an der Tankstelle an und überprüfen Sie den Reifendruck?
Aaron Bertrand
Ja, das habe ich auch gelesen. Wir haben jedoch eine gewisse Leistungsverbesserung festgestellt, wenn wir sie entfragmentiert halten. Die Fragmentierung ist ziemlich vorhersehbar (Tabelle und Zeit), daher werden wir sie nur automatisieren. Ich wollte nur sicherstellen, dass ich mit dem REORGANISIEREN über das REBUILD einverstanden bin, bevor es automatisiert wird.
Vaccano
1
@Vaccano Was bedeutet "ein bisschen"? Wie genau haben Sie diese Dinge zusammengebunden? Möglicherweise ist eine nachfolgende Abfrage schneller, da durch die Indexoperation alle Daten in den Speicher gezogen wurden, sodass die Abfrage dies nicht tun musste. Möglicherweise wurde ein neuer Plan auf der Grundlage aktualisierter Statistiken erstellt, der möglicherweise ein manueller Bestandteil Ihrer Wartung ist oder nicht. Ich bin nicht davon überzeugt, dass Sie Leistungsverbesserungen direkt mit dem Defragmentierungsvorgang verknüpfen können, insbesondere wenn Sie keinen Unterschied in der Fragmentierungsreduzierung zwischen Neuaufbau und Neuorganisation feststellen.
Aaron Bertrand
1
Und wieder sage ich absolut nicht, dass Sie nicht defragmentieren sollten oder dass es ignoriert werden sollte. Stellen Sie nur sicher, dass Sie ihm die Anerkennung geben, die er verdient, und gehen Sie nicht davon aus, dass sich dies (oder nicht) unbedingt direkt auf die Leistung auswirken muss.
Aaron Bertrand
7

@ AaronBertrand hat eine sehr gute Antwort und ist richtig - es kommt darauf an. Ich möchte hinzufügen, dass Sie nur eine Metrik betrachten - die Indexfragmentierung. Das ist ein guter Anfang, aber es gibt noch andere Dinge zu beachten.

Stellen Sie sich das folgende Szenario vor (mit AdventureWorks2014):

select * 
from Sales.SalesOrderDetail
where SalesOrderID < 50000;

--modify
delete 
from Sales.SalesOrderDetail
where SalesOrderID < 50000;
go

select 
    SchemaName = s.name,
    TableName = t.name, 
    IndexName = idx.name, 
    StatsName = st.name, 
    AvgFragmentationPct = idx.avg_fragmentation_in_percent,
    StatsModifications = st.modification_counter,
    StatsPctModified = 100.*st.modification_counter / st.unfiltered_rows,
    StatsSampleRate = st.sample_rate, 
    StatsLastUpdate = st.last_updated,
    Rows = st.rows
from (
    select s.object_id, s.name, sp.modification_counter, sp.unfiltered_rows, s.stats_id, sp.last_updated, sample_rate = (100.*sp.rows_sampled)/sp.unfiltered_rows , sp.rows
    from sys.stats s 
    cross apply sys.dm_db_stats_properties(s.object_id,s.stats_id) sp 
) st
left join (
        select ips.object_id, i.name, ips.partition_number, ips.avg_fragmentation_in_percent, i.index_id
        from sys.dm_db_index_physical_stats(db_id(),null, null, null, default) ips
        join sys.indexes i 
            on ips.index_id = i.index_id
            and ips.object_id = i.object_id
        ) idx
on st.object_id = idx.object_id
    and st.stats_id = idx.index_id
join sys.tables t 
    on st.object_id = t.object_id
join sys.schemas s
    on t.schema_id = s.schema_id
where s.name = 'Sales' and t.name = 'SalesOrderDetail'
go

delete 
from Sales.SalesOrderDetail
where ProductID = 779
go

select 
    SchemaName = s.name,
    TableName = t.name, 
    IndexName = idx.name, 
    StatsName = st.name, 
    AvgFragmentationPct = idx.avg_fragmentation_in_percent,
    StatsModifications = st.modification_counter,
    StatsPctModified = 100.*st.modification_counter / st.unfiltered_rows,
    StatsSampleRate = st.sample_rate, 
    StatsLastUpdate = st.last_updated,
    Rows = st.rows
from (
    select s.object_id, s.name, sp.modification_counter, sp.unfiltered_rows, s.stats_id, sp.last_updated, sample_rate = (100.*sp.rows_sampled)/sp.unfiltered_rows , sp.rows
    from sys.stats s 
    cross apply sys.dm_db_stats_properties(s.object_id,s.stats_id) sp 
) st
left join (
        select ips.object_id, i.name, ips.partition_number, ips.avg_fragmentation_in_percent, i.index_id
        from sys.dm_db_index_physical_stats(db_id(),null, null, null, default) ips
        join sys.indexes i 
            on ips.index_id = i.index_id
            and ips.object_id = i.object_id
        ) idx
on st.object_id = idx.object_id
    and st.stats_id = idx.index_id
join sys.tables t 
    on st.object_id = t.object_id
join sys.schemas s
    on t.schema_id = s.schema_id
where s.name = 'Sales' and t.name = 'SalesOrderDetail'
go

Wir erstellen ein neues automatisch erstelltes Statistikobjekt ( _WA_Sys_00000006_44CA3770in diesem Beispiel) durch Filtern SalesOrderIDund löschen dann Zeilen (~ 30.000 davon). Wir führen dann weitere Änderungen ein, indem wir Zeilen mit einer bestimmten löschen ProductID. Dies ist wichtig, da es sich um eine führende Spalte in mindestens einem dieser Indizes / Statistiken handelt, die wiederum aus Gründen der Selektivitätsberechnung (Statistik) und der B-Tree-Durchquerung (Index) wichtig ist.

Geben Sie hier die Bildbeschreibung ein

Die Indexfragmentierung ist nicht so schlecht, also lasst uns neu organisieren.

alter index all on Sales.SalesOrderDetail reorganize;
go

select 
    SchemaName = s.name,
    TableName = t.name, 
    IndexName = idx.name, 
    StatsName = st.name, 
    AvgFragmentationPct = idx.avg_fragmentation_in_percent,
    StatsModifications = st.modification_counter,
    StatsPctModified = 100.*st.modification_counter / st.unfiltered_rows,
    StatsSampleRate = st.sample_rate, 
    StatsLastUpdate = st.last_updated,
    Rows = st.rows
from (
    select s.object_id, s.name, sp.modification_counter, sp.unfiltered_rows, s.stats_id, sp.last_updated, sample_rate = (100.*sp.rows_sampled)/sp.unfiltered_rows , sp.rows
    from sys.stats s 
    cross apply sys.dm_db_stats_properties(s.object_id,s.stats_id) sp 
) st
left join (
        select ips.object_id, i.name, ips.partition_number, ips.avg_fragmentation_in_percent, i.index_id
        from sys.dm_db_index_physical_stats(db_id(),null, null, null, default) ips
        join sys.indexes i 
            on ips.index_id = i.index_id
            and ips.object_id = i.object_id
        ) idx
on st.object_id = idx.object_id
    and st.stats_id = idx.index_id
join sys.tables t 
    on st.object_id = t.object_id
join sys.schemas s
    on t.schema_id = s.schema_id
where s.name = 'Sales' and t.name = 'SalesOrderDetail'
go

Geben Sie hier die Bildbeschreibung ein

Durch eine Umstrukturierung werden keine Änderungen vorgenommen.

Lassen Sie uns wieder aufbauen:

alter index all on Sales.SalesOrderDetail rebuild;
go

select 
    SchemaName = s.name,
    TableName = t.name, 
    IndexName = idx.name, 
    StatsName = st.name, 
    AvgFragmentationPct = idx.avg_fragmentation_in_percent,
    StatsModifications = st.modification_counter,
    StatsPctModified = 100.*st.modification_counter / st.unfiltered_rows,
    StatsSampleRate = st.sample_rate, 
    StatsLastUpdate = st.last_updated,
    Rows = st.rows
from (
    select s.object_id, s.name, sp.modification_counter, sp.unfiltered_rows, s.stats_id, sp.last_updated, sample_rate = (100.*sp.rows_sampled)/sp.unfiltered_rows , sp.rows
    from sys.stats s 
    cross apply sys.dm_db_stats_properties(s.object_id,s.stats_id) sp 
) st
left join (
        select ips.object_id, i.name, ips.partition_number, ips.avg_fragmentation_in_percent, i.index_id
        from sys.dm_db_index_physical_stats(db_id(),null, null, null, default) ips
        join sys.indexes i 
            on ips.index_id = i.index_id
            and ips.object_id = i.object_id
        ) idx
on st.object_id = idx.object_id
    and st.stats_id = idx.index_id
join sys.tables t 
    on st.object_id = t.object_id
join sys.schemas s
    on t.schema_id = s.schema_id
where s.name = 'Sales' and t.name = 'SalesOrderDetail'
go

Geben Sie hier die Bildbeschreibung ein

Ok, unsere Fragmentierungszahlen sind bescheiden besser, aber nicht signifikant und Ihrer Meinung nach den Aufwand für den Wiederaufbau im Vergleich zur Reorganisation möglicherweise nicht wert.

Es gibt jedoch noch ein paar andere erwähnenswerte Dinge.

  1. Durch die Neuerstellung Ihrer Indizes werden auch Ihre Statistiken mit einem vollständigen Scan aktualisiert. Es sollte beachtet werden, dass nur die Statistiken aktualisiert werden, die den Index unterstützen - es werden keine anderen Statistiken aktualisiert (wie durch den traurigen Zustand von belegt _WA_Sys_00000006_44CA3770).
  2. Durch die Neuorganisation Ihres Index werden Ihre Statistiken in keiner Weise aktualisiert

Fazit

Es gibt mehr zu bewerten, als ob Sie gute Defragmentierungsraten erhalten oder nicht. Obwohl dies für IO sicherlich wichtig ist, fand ich es auch sehr hilfreich, meine Systeme zu erkunden und zu prüfen, ob ich feststellen kann, wie ich sie am besten warten kann, anstatt sie blind zu aktualisieren, neu zu erstellen und neu zu organisieren.

Swasheck
quelle
7

Der große Unterschied in meiner Umgebung besteht darin, dass Reorganize Single-Threaded ist und Rebuild so parallel wie Prozessoren ausgeführt werden kann. Die Neuerstellung bietet außerdem den zusätzlichen Vorteil, dass Sie Ihre Statistiken aktualisieren können, sodass Sie auf separate Statistikaktualisierungen verzichten können, wenn Sie sie neu erstellt haben.

Aus meiner Sicht habe ich bei einigen großen Tabellen (100 GB bis Multi-Terabyte) so ziemlich alles neu erstellt. Ich habe gesehen, wie Reorganize 8 Stunden mit einem PK (300 GB Tisch) verbracht und kaum eine Beule gemacht hat. Ich bin allein verantwortlich für etwa 100 TB Daten auf 8 Servern, und unsere Wartungsfenster sind nicht die längsten (1 bis 7 Uhr morgens).

Ich verwende derzeit Ola Hallengren- Skripte, möchte aber in den kommenden Monaten zu Minion Reindex wechseln , da sie die Möglichkeit bieten, die Objekte, an denen Sie arbeiten möchten , vorab abzurufen, sodass das gesamte Wartungsfenster genutzt werden kann bei der Wartung, anstatt Fragmentierungsdaten zu sammeln. Die Funktion zum Sammeln von Fragmentierungsdaten kann auch im LIMITED-Modus für größere Tabellen eine Weile ausgeführt werden.

Erik Darling
quelle