Können SQL Server-Systemtabellen defragmentiert werden?

15

Wir haben mehrere Datenbanken, in denen eine große Anzahl von Tabellen erstellt und gelöscht werden. Nach unseren Erkenntnissen führt SQL Server keine internen Wartungsarbeiten an den Systembasistabellen durch , was bedeutet, dass sie im Laufe der Zeit sehr fragmentiert und in ihrer Größe aufgebläht werden können. Dies setzt den Pufferpool unnötig unter Druck und wirkt sich auch negativ auf die Leistung von Vorgängen aus, z. B. die Berechnung der Größe aller Tabellen in einer Datenbank.

Hat jemand Vorschläge zur Minimierung der Fragmentierung in diesen internen Kerntabellen? Eine naheliegende Lösung besteht darin, zu vermeiden, dass so viele Tabellen erstellt werden (oder dass alle temporären Tabellen in Tempdb erstellt werden). Zum Zweck dieser Frage wird jedoch angenommen, dass die Anwendung nicht über diese Flexibilität verfügt.

Bearbeiten: Weitere Untersuchungen zeigen diese unbeantwortete Frage , die eng verwandt aussieht und darauf hinweist, dass eine Form der manuellen Wartung über ALTER INDEX...REORGANIZEeine Option sein kann.


Anfängliche Forschung

Metadaten zu diesen Tabellen können in folgenden Formaten angezeigt werden sys.dm_db_partition_stats:

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136

Scheint sys.dm_db_index_physical_statsjedoch nicht zu unterstützen, die Fragmentierung dieser Tabellen anzuzeigen:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
    DB_ID(),
    OBJECT_ID('sys.syscolpars'),
    NULL,
    NULL,
    'DETAILED'
)

Die Skripte von Ola Hallengren enthalten auch einen Parameter, der die Defragmentierung von is_ms_shipped = 1Objekten berücksichtigt. Die Prozedur ignoriert jedoch unbemerkt die Systembasistabellen, auch wenn dieser Parameter aktiviert ist. Ola stellte klar, dass dies das erwartete Verhalten ist. Es werden nur Benutzertabellen (keine Systemtabellen msdb.dbo.backupset) berücksichtigt , die (zB ) ms_shipped sind.

-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
        @FragmentationLow = 'INDEX_REORGANIZE',
        @FragmentationMedium = 'INDEX_REORGANIZE',
        @FragmentationHigh = 'INDEX_REORGANIZE',
        @PageCountLevel = 0,
        @UpdateStatistics = 'ALL',
        @Indexes = '%Test.sys.sysrowsets.%',
        -- Proc works properly if targeting a non-system table instead
        --@Indexes = '%Test.dbo.Numbers.%',
        @MSShippedObjects = 'Y',
        @Execute = 'N';
PRINT(@result);


Zusätzliche angeforderte Informationen

Ich habe eine Anpassung von Aarons Abfrage unterhalb der Verwendung des Pufferpools für Inspect-Systemtabellen verwendet. Dabei stellte sich heraus, dass sich für nur eine Datenbank Dutzende von GB Systemtabellen im Pufferpool befinden, wobei in einigen Fällen ~ 80% dieses Speicherplatzes freier Speicherplatz sind .

-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
    COUNT(b.page_id) pages,
    SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
    ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
    ON p.partition_id = a.container_id
    AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC

Bildbeschreibung hier eingeben

Geoff Patterson
quelle

Antworten:

11

Sind Sie sicher, dass Sie diese Systemtabelle als einzige Quelle für "unnötigen Druck auf den Pufferpool und negative Auswirkungen auf die Leistung von Vorgängen wie die Berechnung der Größe aller Tabellen in einer Datenbank" positiv und genau identifiziert haben? Sind Sie sicher, dass diese Systemtabelle nicht so selbst verwaltet wird, dass (a) die Fragmentierung minimiert oder geheim unter Kontrolle gehalten wird, oder nur (b) effizient im Arbeitsspeicher verwaltet wird, sodass die Defragmentierungsstufen wirklich keine großen Auswirkungen haben?

Sie können sehen , wie viele Seiten in Gebrauch sind, und Sie können wie viel freier Speicherplatz siehe ist die Seiten , die im Speicher sind ( page_free_space_percentimmer NULLin den Zuteilungen DMF, aber dies ist aus dem Puffer verfügbar DMV) - das Ihnen eine Vorstellung geben sollte Wenn das, worüber Sie sich Sorgen machen, wirklich etwas ist, über das Sie sich Sorgen machen sollten:

SELECT 
  Number_of_Pages = COUNT(*), 
  Number_of_Pages_In_Memory = COUNT(b.page_id),
  Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0) 
FROM sys.dm_db_database_page_allocations
(
  DB_ID(),
  OBJECT_ID(N'sys.syscolpars'),
  NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID() 
AND b.page_id = p.allocated_page_page_id 
AND b.file_id = p.allocated_page_file_id;

Wenn Ihre Seitenzahl gering ist (z. B. <10000 für Systemtabellen) oder wenn der freie Speicherplatz "niedrig" ist (Sie sind sich nicht sicher, welche Schwellenwerte für Reorg / Rebuild typisch sind), konzentrieren Sie sich auf andere, interessantere, niedrig hängende Früchte .

Wenn Ihre Seitenzahl groß und der freie Speicherplatz "hoch" ist, gebe ich SQL Server möglicherweise zu viel Anerkennung für seine eigene Selbstwartung. Wie Sie anhand der anderen Frage gezeigt haben , funktioniert dies ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... und tut Fragmentierung reduzieren. Möglicherweise sind jedoch erhöhte Berechtigungen erforderlich (ich habe es nicht als Peon versucht).

Möglicherweise können Sie dies im Rahmen Ihrer eigenen Wartung nur in regelmäßigen Abständen tun, wenn Sie sich gut fühlen und / oder wenn Sie irgendwelche Beweise dafür haben, dass es sich überhaupt positiv auf Ihr System auswirkt.

Aaron Bertrand
quelle
Ich habe eine weitere Antwort hinzugefügt, die zusammenfasst, was wir letztendlich gemacht haben, und dann die vorherigen Kommentare hier bereinigt. Danke nochmal für deine Hilfe!
Geoff Patterson
7

Auf der Grundlage von Aarons Antworten und zusätzlichen Nachforschungen finden Sie hier eine kurze Beschreibung meines Ansatzes.

Soweit ich weiß, sind die Möglichkeiten zur Überprüfung der Fragmentierung von Systembasistabellen begrenzt. Ich habe ein Connect-Problem eingereicht , um eine bessere Sichtbarkeit zu gewährleisten. In der Zwischenzeit scheinen jedoch Optionen wie die Überprüfung des Pufferpools oder die Überprüfung der durchschnittlichen Anzahl von Bytes pro Zeile zu bestehen.

Ich habe dann eine Prozedur erstellt, um ALTER INDEX ... REORGANIZE für alle System-Basistabellen durchzuführen . Die Ausführung dieser Prozedur auf einigen unserer am häufigsten (ab) verwendeten Dev-Server ergab, dass die kumulative Größe der System-Basistabellen um bis zu 50 GB reduziert wurde (mit ~ 5 MM Benutzertabellen auf dem System, also eindeutig ein Extremfall).

Eine unserer nächtlichen Wartungsaufgaben, mit deren Hilfe viele der Benutzertabellen, die durch verschiedene Komponententests und -entwicklungen erstellt wurden, bereinigt werden konnten, dauerte zuvor ~ 50 Minuten. Eine Kombination aus sp_whoisactive, sys.dm_os_waiting_tasksund DBCC PAGEzeigte, dass die Wartezeiten von E / A auf den Systembasistabellen dominiert wurden.

Nach der Reorganisation aller Systembasistabellen sank die Wartungsaufgabe auf ~ 15 Minuten. Es gab immer noch einige E / A-Wartezeiten, die jedoch erheblich verringert wurden, möglicherweise aufgrund einer größeren Menge der im Cache verbleibenden Daten und / oder aufgrund einer geringeren Fragmentierung mehr Readaheads.

Daher ist meine Schlussfolgerung, dass das Hinzufügen ALTER INDEX...REORGANIZEvon Systembasistabellen zu einem Wartungsplan möglicherweise eine nützliche Sache ist, aber wahrscheinlich nur, wenn Sie ein Szenario haben, in dem eine ungewöhnliche Anzahl von Objekten in einer Datenbank erstellt wird.

Geoff Patterson
quelle
+1 sowohl für Ihre Frage als auch für die Antwort - Interna sind eine Art Black Box, und Sie haben dabei geholfen, etwas Licht in ein wirklich unangenehmes Szenario für die Leistung zu bringen (auch wenn es sich bei Ihrem um einen Randfall handelt ).
Max Vernon