我们有几个数据库,在其中创建和删除了大量表。据我们所知,SQL Server不会对系统基表进行任何内部维护,这意味着它们随着时间的流逝会变得非常零散,并且大小会膨胀。这给缓冲池造成了不必要的压力,并且还负面影响了操作的性能,例如计算数据库中所有表的大小。
有没有人建议尽量减少这些核心内部表上的碎片?一个显而易见的解决方案可以避免创建太多表(或在tempdb中创建所有临时表),但是出于这个问题的目的,我们可以说应用程序没有这种灵活性。
编辑:进一步的研究显示了这个悬而未决的问题,该问题看起来密切相关,并且表明可以选择某种形式的手动维护ALTER INDEX...REORGANIZE
。
初步研究
有关这些表的元数据可以在以下位置查看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
但是,sys.dm_db_index_physical_stats
似乎不支持查看这些表的碎片:
-- 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'
)
Ola Hallengren的脚本还包含一个用于考虑is_ms_shipped = 1
对象碎片整理的参数,但是即使启用了此参数,该过程也会默默地忽略系统基表。奥拉澄清说,这是预期的行为。仅msdb.dbo.backupset
考虑ms_shipped的用户表(而不是系统表)(例如)。
-- 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);
其他要求的信息
我在检查系统表缓冲池使用情况下使用了Aaron查询的一种改编形式,发现在缓冲池中只有一个数据库有数十GB的系统表,在某些情况下,约80%的空间是可用空间。
-- 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