Wenn der Index nicht mehr weiĂ, wo oben ist
Indexe in SQL Server sind wie Karteikarten.
Wenn sie zu oft umsortiert, gelöscht und beschrieben werden,
stehen sie irgendwann kreuz und quer.
Das kostet Performance.
Vor allem bei groĂen Tabellen.
Und bei Joins.
Was bei Fragmentierung passiert
- SQL Server muss mehr Seiten lesen
- Mehr Leseoperationen = mehr I/O
- Mehr CPU durch ungĂŒnstige PlĂ€ne
- Langsame Abfragen, obwohl Index da ist
Ab 5 % Fragmentierung solltest Du aufrÀumen.
Ab 30 % wirdâs Zeit fĂŒr einen Rebuild.
Unterschied: Reorganize vs. Rebuild
MaĂnahme | Fragmentierung ab | Sperrt Tabelle | Statistiken neu? | Logging |
---|---|---|---|---|
Reorganize | 5 % | Nein | Nein | minimal |
Rebuild | 30 % | Ja (Offline) | Ja | mehr Log |
Online-Rebuild geht nur in der Enterprise Edition.
Sonst steht die Tabelle kurz still.
Beispiel: Manuelle Analyse und Pflege
-- Fragmentierung auslesen
SELECT
OBJECT_NAME(i.object_id) AS Tabelle,
i.name AS Indexname,
ips.avg_fragmentation_in_percent,
ips.page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.page_count > 100
ORDER BY ips.avg_fragmentation_in_percent DESC;
Dann gezielt reorganisieren oder rebuilden:
-- Reorganize
ALTER INDEX [IX_Kunden_Name] ON dbo.Kunden REORGANIZE;
-- Rebuild
ALTER INDEX [IX_Kunden_Name] ON dbo.Kunden REBUILD WITH (FILLFACTOR = 90);
Automatisiert: Dynamisches Skript zur Pflege
DECLARE @Tabelle SYSNAME
DECLARE @Index SYSNAME
DECLARE @SQL NVARCHAR(MAX)
DECLARE cur CURSOR FOR
SELECT
OBJECT_NAME(i.object_id),
i.name
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 5
AND ips.page_count > 100;
OPEN cur
FETCH NEXT FROM cur INTO @Tabelle, @Index
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = '
IF EXISTS (
SELECT 1
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N''' + @Tabelle + '''), NULL, NULL, ''LIMITED'') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE i.name = ''' + @Index + ''' AND ips.avg_fragmentation_in_percent BETWEEN 5 AND 30
)
ALTER INDEX [' + @Index + '] ON [' + @Tabelle + '] REORGANIZE;
ELSE
ALTER INDEX [' + @Index + '] ON [' + @Tabelle + '] REBUILD WITH (FILLFACTOR = 90);'
EXEC sp_executesql @SQL
FETCH NEXT FROM cur INTO @Tabelle, @Index
END
CLOSE cur
DEALLOCATE cur
LĂ€uft idealerweise nachts oder am Wochenende im SQL Agent.
Nur auf produktionsfernen Zeitfenstern.
Optional: Statistiken aktualisieren
Nach einem Rebuild sind die Statistiken frisch.
Nach Reorganize nicht.
Darum:
EXEC sp_updatestats;
Einmal pro Woche reicht bei den meisten KMU.
Monitoring: Letzte Indexpflege prĂŒfen
SELECT
OBJECT_NAME(i.object_id) AS Tabelle,
i.name AS Indexname,
s.last_user_update
FROM sys.dm_db_index_usage_stats s
JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
WHERE database_id = DB_ID()
ORDER BY s.last_user_update DESC;
So erkennst Du, ob ein Index ĂŒberhaupt noch gebraucht wird.
Oder ob Du besser gleich ausmisten solltest.
Mein Setup in der Praxis
Aufgabe | Intervall | Werkzeug |
---|---|---|
Fragmentierung prĂŒfen | wöchentlich | SQL Agent Job |
Reorg/Rebuild starten | automatisch | per Cursor / Skript |
Stats aktualisieren | wöchentlich | sp_updatestats |
Monitoring | monatlich | Reporting via View |
Doku | jÀhrlich | Export aus sys.indexes |
Ein Index ist kein Kunstwerk
Er muss funktionieren â nicht schön aussehen.
Aber wenn er fragmentiert ist, bringt er niemandem was.
Pflege ihn.
Automatisch. RegelmĂ€Ăig.
Dann lÀuft der Laden. Auch ohne Drama.
No responses yet