sp_spaceused - 如何在SQL中的所有表中测量GB的大小

问题描述 投票:8回答:4

How to measure table size in GB in a table in SQL讨论之后,我正在寻找一种解决方案来使用存储过程sp_spaceused单独测量SQL Server的所有表所使用的空间。

sql sql-server size
4个回答
13
投票

以下基本查询有效。它使用相同的算法获得与sp_spaceused相同的输出,但效率更高。请不要使用CURSOR + sp_spaceused方法;绝对没有理由这样做。使用sp_spaceused的一个潜在问题是它应该是一个报告proc,因此输出是所有文本,而不是实际数字,并且将其解析为数字可能容易出错。

最好不要使用sys.tablessp_msforeachtable,因为它们都排除了索引视图。

以下内容与sp_spaceused完全相同:

  • 包括XML索引,FullText索引,索引视图等。
  • 细分所使用的数据与索引空间的信息

如果您需要它可以用于所有数据库,它也可以很容易地适应它。

如果您需要按索引分解这些数据,我在DBA.StackExchange上调整了以下查询以回答这个问题:space usage on sys.allocation_units and sp_spaceused

;WITH extra AS
(   -- Get info for FullText indexes, XML Indexes, etc
    SELECT  sit.[object_id],
            sit.[parent_id],
            ps.[index_id],
            SUM(ps.reserved_page_count) AS [reserved_page_count],
            SUM(ps.used_page_count) AS [used_page_count]
    FROM    sys.dm_db_partition_stats ps
    INNER JOIN  sys.internal_tables sit
            ON  sit.[object_id] = ps.[object_id]
    WHERE   sit.internal_type IN
               (202, 204, 207, 211, 212, 213, 214, 215, 216, 221, 222, 236)
    GROUP BY    sit.[object_id],
                sit.[parent_id],
                ps.[index_id]
), agg AS
(   -- Get info for Tables, Indexed Views, etc (including "extra")
    SELECT  ps.[object_id] AS [ObjectID],
            ps.index_id AS [IndexID],
            SUM(ps.in_row_data_page_count) AS [InRowDataPageCount],
            SUM(ps.used_page_count) AS [UsedPageCount],
            SUM(ps.reserved_page_count) AS [ReservedPageCount],
            SUM(ps.row_count) AS [RowCount],
            SUM(ps.lob_used_page_count + ps.row_overflow_used_page_count)
                    AS [LobAndRowOverflowUsedPageCount]
    FROM    sys.dm_db_partition_stats ps
    GROUP BY    ps.[object_id],
                ps.[index_id]
    UNION ALL
    SELECT  ex.[parent_id] AS [ObjectID],
            ex.[object_id] AS [IndexID],
            0 AS [InRowDataPageCount],
            SUM(ex.used_page_count) AS [UsedPageCount],
            SUM(ex.reserved_page_count) AS [ReservedPageCount],
            0 AS [RowCount],
            0 AS [LobAndRowOverflowUsedPageCount]
    FROM    extra ex
    GROUP BY    ex.[parent_id],
                ex.[object_id]
), spaceused AS
(
SELECT  agg.[ObjectID],
        OBJECT_SCHEMA_NAME(agg.[ObjectID]) AS [SchemaName],
        OBJECT_NAME(agg.[ObjectID]) AS [TableName],
        SUM(CASE
                WHEN (agg.IndexID < 2) THEN agg.[RowCount]
                ELSE 0
            END) AS [Rows],
        SUM(agg.ReservedPageCount) * 8 AS [ReservedKB],
        SUM(agg.LobAndRowOverflowUsedPageCount +
            CASE
                WHEN (agg.IndexID < 2) THEN (agg.InRowDataPageCount)
                ELSE 0
            END) * 8 AS [DataKB],
        SUM(agg.UsedPageCount - agg.LobAndRowOverflowUsedPageCount -
            CASE
                WHEN (agg.IndexID < 2) THEN agg.InRowDataPageCount
                ELSE 0
            END) * 8 AS [IndexKB],
        SUM(agg.ReservedPageCount - agg.UsedPageCount) * 8 AS [UnusedKB],
        SUM(agg.UsedPageCount) * 8 AS [UsedKB]
FROM    agg
GROUP BY    agg.[ObjectID],
            OBJECT_SCHEMA_NAME(agg.[ObjectID]),
            OBJECT_NAME(agg.[ObjectID])
)
SELECT sp.SchemaName,
       sp.TableName,
       sp.[Rows],
       sp.ReservedKB,
       (sp.ReservedKB / 1024.0 / 1024.0) AS [ReservedGB],
       sp.DataKB,
       (sp.DataKB / 1024.0 / 1024.0) AS [DataGB],
       sp.IndexKB,
       (sp.IndexKB / 1024.0 / 1024.0) AS [IndexGB],
       sp.UsedKB AS [UsedKB],
       (sp.UsedKB / 1024.0 / 1024.0) AS [UsedGB],
       sp.UnusedKB,
       (sp.UnusedKB / 1024.0 / 1024.0) AS [UnusedGB],
       so.[type_desc] AS [ObjectType],
       so.[schema_id] AS [SchemaID],
       sp.ObjectID
FROM   spaceused sp
INNER JOIN sys.all_objects so
        ON so.[object_id] = sp.ObjectID
WHERE so.is_ms_shipped = 0
--so.[name] LIKE N''  -- optional name filter
--ORDER BY ??

6
投票

我知道这不是你要求的,因为它不使用sp_spaceused但这将提供你所追求的结果。

SELECT  
    s.Name AS SchemaName,
    t.NAME AS TableName,
    p.rows AS RowCounts,
    SUM(a.total_pages) * 8 AS TotalSpaceKB,
    ( SUM(a.total_pages) * 8 ) / 1024.0 AS TotalSpaceMB,
    (( SUM(a.total_pages) * 8 ) / 1024.0)/1024.0 AS TotalSpaceGB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB,
    ( SUM(a.used_pages) * 8 ) / 1024.0 AS UsedSpaceMB,
    (( SUM(a.used_pages) * 8 ) / 1024.0) /1024.0 AS UsedSpaceGB,
    ( SUM(a.total_pages) - SUM(a.used_pages) ) * 8 AS UnusedSpaceKB,
    ( ( SUM(a.total_pages) - SUM(a.used_pages) ) * 8 ) / 1024.0 AS UnusedSpaceMB,
    (( ( SUM(a.total_pages) - SUM(a.used_pages) ) * 8 ) / 1024.0)/1024.0 AS UnusedSpaceGB,
   GROUPING(t.Name)
FROM    sys.tables t
    INNER JOIN sys.schemas s ON s.schema_id = t.schema_id
    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
WHERE   t.NAME NOT LIKE 'dt%'
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
GROUP BY s.Name,
     t.Name,
    p.Rows
   WITH ROLLUP
   ORDER BY s.Name,
    t.Name

如果您确实需要使用sp_spaceused,请告诉我。


5
投票

这里有几个选项:

sp_msforeachtable

sp_msforeachtable 'exec sp_spaceused [?]'

虽然可以使用sp_msforeachtable,但是有一些限制:

  • 首先,您最终会为每个运行的表生成一个结果集,这很难处理
  • 如果你在太多的表上运行它,那么你就达到了SSMS支持的结果集的限制(想想这通常在200左右)

整理结果

通过更多工作,我们可以将所有结果整理成单个数据集,从而避免这些限制。每当需要使用不同的参数运行sproc多次并且整理来自那些运行的结果时,该解决方案的模式是类似的。

--Get list of interesting tables
declare @tables table(id int identity(1,1), name varchar(200))
declare @tablename varchar(200)
insert @tables
select table_name from information_schema.tables where table_type = 'BASE TABLE'

--Define table for results
declare @info table(name varchar(200), rows bigint, reserved varchar(200), data varchar(200), index_size varchar(200), unused varchar(200))

--Working vars
declare @max int, @pos int
select @max = count(1), @pos = 1 from @tables

--Loop to get all results
while @pos <= @max
begin

    select @tablename = name from @tables where id = @pos

    insert @info
    exec sp_spaceused @tablename

    set @pos = @pos + 1
end

--return all results
select * from @info

我更喜欢使用变量表,但也可以使用游标/临时表。


0
投票

我假设您尝试使用sp_spaceused来查找数据库中所有表的大小?

如果是这样,你可以这样做:

USE database_name
GO
sp_msforeachtable 'exec sp_spaceused [?]'
© www.soinside.com 2019 - 2024. All rights reserved.