Kami memiliki beberapa database tempat sejumlah besar tabel dibuat dan dihapus. Dari apa yang dapat kami katakan, SQL Server tidak melakukan pemeliharaan internal pada tabel basis sistem , yang berarti bahwa mereka dapat menjadi sangat terfragmentasi dari waktu ke waktu dan ukurannya membengkak. Ini memberikan tekanan yang tidak perlu pada kumpulan buffer dan juga berdampak negatif pada kinerja operasi seperti menghitung ukuran semua tabel dalam database.
Adakah yang punya saran untuk meminimalkan fragmentasi pada tabel internal inti ini? Satu solusi yang jelas bisa untuk menghindari membuat begitu banyak tabel (atau untuk membuat semua tabel sementara di tempdb), tetapi untuk tujuan pertanyaan ini, katakanlah bahwa aplikasi tidak memiliki fleksibilitas itu.
Sunting: Penelitian lebih lanjut menunjukkan pertanyaan yang tidak terjawab ini , yang terlihat terkait erat dan menunjukkan bahwa beberapa bentuk pemeliharaan manual ALTER INDEX...REORGANIZE
dapat menjadi pilihan.
Penelitian awal
Metadata tentang tabel ini dapat dilihat di 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
Namun, sys.dm_db_index_physical_stats
tampaknya tidak mendukung tampilan fragmentasi tabel ini:
-- 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'
)
Script Ola Hallengren juga mengandung parameter untuk mempertimbangkan defragmentasi untuk is_ms_shipped = 1
objek, tetapi prosedur ini secara diam-diam mengabaikan tabel basis sistem bahkan dengan parameter ini diaktifkan. Ola mengklarifikasi bahwa ini adalah perilaku yang diharapkan; hanya tabel pengguna (bukan tabel sistem) yang ms_shipped (mis. msdb.dbo.backupset
) yang dipertimbangkan.
-- 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);
Info tambahan yang diminta
Saya menggunakan adaptasi dari permintaan Harun di bawah penggunaan tabel penyangga tabel sistem memeriksa, dan ini menemukan bahwa ada puluhan GB tabel sistem di kolam penyangga hanya untuk satu database, dengan ~ 80% dari ruang itu menjadi ruang bebas dalam beberapa kasus .
-- 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