You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取近6个月内所有数据库表的UsedSpaceMB数据

如何查询SQL Server中所有表近6个月数据的占用空间(UsedSpaceMB)

需求:获取数据库中所有表近6个月数据的占用空间(UsedSpaceMB)。

当前使用的查询语句返回的是表创建以来的总空间大小:

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows,
    SUM(a.total_pages) * 8 AS TotalSpaceKB, 
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB, 
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB, 
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB 
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    TotalSpaceMB DESC, t.Name

自定义尝试的查询仍返回总空间大小,未达到需求:

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows,
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB,
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB,
    t.modify_date AS ModifyDate
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.modify_date >= Dateadd(Month, Datediff(Month, 0, DATEADD(m, -6, current_timestamp)), 0)
    AND t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.Name, p.Rows, t.modify_date
ORDER BY 
    TotalSpaceMB DESC, t.Name, t.modify_date;

问题原因

你使用t.modify_date过滤的是表结构的修改时间,不是数据的更新/插入时间,因此无法筛选出近6个月数据的空间。同时,sys.allocation_units等系统视图统计的是整个表的物理空间,无法直接按数据时间范围拆分空间占用。

解决方案

根据表的存储方式,分两种情况处理:

1. 表包含数据时间字段(如CreateTime、UpdateTime)

如果表中有记录数据插入/更新时间的字段,可以通过统计近6个月数据的行数占比,估算对应的空间占用(该方法为近似值,因为每行数据大小可能不一致):

WITH TableTotalSpace AS (
    -- 先统计各表的总空间和总行数
    SELECT 
        t.OBJECT_ID,
        t.NAME AS TableName,
        s.Name AS SchemaName,
        SUM(p.rows) AS TotalRows,
        CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalUsedSpaceMB
    FROM 
        sys.tables t
    INNER JOIN      
        sys.indexes i ON t.OBJECT_ID = i.object_id
    INNER JOIN 
        sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
    INNER JOIN 
        sys.allocation_units a ON p.partition_id = a.container_id
    LEFT OUTER JOIN 
        sys.schemas s ON t.schema_id = s.schema_id
    WHERE 
        t.NAME NOT LIKE 'dt%' 
        AND t.is_ms_shipped = 0
        AND i.OBJECT_ID > 255 
    GROUP BY 
        t.OBJECT_ID, t.Name, s.Name
),
RecentDataRows AS (
    -- 统计各表近6个月的数据行数(需替换为实际时间字段名,比如CreateTime)
    SELECT 
        t.OBJECT_ID,
        t.NAME AS TableName,
        s.Name AS SchemaName,
        COUNT(*) AS RecentRows
    FROM 
        sys.tables t
    LEFT JOIN 
        sys.schemas s ON t.schema_id = s.schema_id
    CROSS APPLY (
        SELECT * FROM [s.Name].[t.Name] 
        WHERE CreateTime >= DATEADD(MONTH, -6, GETDATE()) -- 替换为你的时间字段
    ) AS RecentData
    WHERE 
        t.NAME NOT LIKE 'dt%' 
        AND t.is_ms_shipped = 0
    GROUP BY 
        t.OBJECT_ID, t.Name, s.Name
)
SELECT 
    tts.TableName,
    tts.SchemaName,
    rd.RecentRows AS Recent6MonthsRows,
    tts.TotalRows,
    CAST(ROUND((rd.RecentRows * 1.0 / tts.TotalRows) * tts.TotalUsedSpaceMB, 2) AS NUMERIC(36, 2)) AS Recent6MonthsUsedSpaceMB,
    tts.TotalUsedSpaceMB
FROM 
    TableTotalSpace tts
LEFT JOIN 
    RecentDataRows rd ON tts.OBJECT_ID = rd.OBJECT_ID
ORDER BY 
    Recent6MonthsUsedSpaceMB DESC, tts.TableName;

注意:将代码中的CreateTime替换为表实际的时间字段名。如果表没有时间字段,此方法无法使用。

2. 表按时间分区

如果表是按时间分区(比如每月一个分区),可以直接查询对应分区的空间占用:

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    pf.name AS PartitionFunction,
    ps.name AS PartitionScheme,
    p.partition_number,
    prv.value AS PartitionBoundary,
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB
FROM 
    sys.tables t
INNER JOIN 
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
INNER JOIN 
    sys.partition_schemes ps ON i.data_space_id = ps.data_space_id
INNER JOIN 
    sys.partition_functions pf ON ps.function_id = pf.function_id
LEFT JOIN 
    sys.partition_range_values prv ON pf.function_id = prv.function_id AND p.partition_number = prv.boundary_id
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
    -- 过滤近6个月的分区边界(需根据分区字段类型调整,这里假设是日期类型)
    AND prv.value >= DATEADD(MONTH, -6, GETDATE())
GROUP BY 
    t.Name, s.Name, pf.name, ps.name, p.partition_number, prv.value
ORDER BY 
    UsedSpaceMB DESC, t.Name;

注意:需根据你的分区字段和边界调整prv.value的过滤条件。


内容的提问来源于stack exchange,提问作者Abdul Rehman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:25:35