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...REORGANIZE
eine 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_stats
jedoch 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 = 1
Objekten 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
quelle
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_tasks
undDBCC PAGE
zeigte, 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...REORGANIZE
von 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.quelle