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