Abbiamo diversi database in cui vengono creati e rilasciati un gran numero di tabelle. Da quello che possiamo dire, SQL Server non esegue alcuna manutenzione interna sulle tabelle di base del sistema , il che significa che possono diventare molto frammentati nel tempo e gonfiati di dimensioni. Ciò esercita una pressione non necessaria sul pool di buffer e influisce negativamente anche sulle prestazioni di operazioni come il calcolo delle dimensioni di tutte le tabelle in un database.
Qualcuno ha suggerimenti per ridurre al minimo la frammentazione su queste tabelle interne core? Una soluzione ovvia potrebbe evitare di creare così tante tabelle (o creare tutte le tabelle temporanee in tempdb), ma ai fini di questa domanda diciamo che l'applicazione non ha quella flessibilità.
Modifica: ulteriori ricerche mostrano questa domanda senza risposta , che sembra strettamente correlata e indica che una qualche forma di manutenzione manuale tramite ALTER INDEX...REORGANIZE
potrebbe essere un'opzione.
Ricerca iniziale
I metadati su queste tabelle possono essere visualizzati in 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
Tuttavia, sys.dm_db_index_physical_stats
non sembra supportare la visualizzazione della frammentazione di queste tabelle:
-- 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'
)
Gli script di Ola Hallengren contengono anche un parametro per considerare la deframmentazione per gli is_ms_shipped = 1
oggetti, ma la procedura ignora silenziosamente le tabelle di base del sistema anche con questo parametro abilitato. Ola ha chiarito che questo è il comportamento previsto; vengono prese in msdb.dbo.backupset
considerazione solo le tabelle utente (non le tabelle di sistema) che sono ms_shipped (ad esempio ).
-- 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);
Ulteriori informazioni richieste
Ho usato un adattamento della query di Aaron al di sotto dell'utilizzo del pool buffer della tabella di sistema inspect e questo ha rilevato che ci sono decine di GB di tabelle di sistema nel pool buffer per un solo database, con ~ 80% di quello spazio che è spazio libero in alcuni casi .
-- 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