关于sql server:获取数据库中所有表的大小

Get size of all tables in database

我继承了一个相当大的SQL Server数据库。考虑到它包含的数据,它占用的空间似乎比我预期的要大。

有没有一种简单的方法来确定每个表在磁盘上消耗多少空间?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SELECT
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    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
    t.Name


如果您使用的是SQL Server Management Studio(SSMS),则可以运行标准报表,而不是运行查询(在我的示例中,查询返回了重复的行)。

  • 右键单击数据库
  • 导航到报告>标准报告>磁盘使用情况(按表)
  • 注意:必须将数据库兼容级别设置为90或更高才能使其正常工作。请参阅http://msdn.microsoft.com/en-gb/library/bb510680.aspx


    sp u space used可以获取有关表、索引视图或整个数据库使用的磁盘空间的信息。

    例如:

    1
    2
    3
    USE MyDatabase; GO

    EXEC sp_spaceused N'User.ContactInfo'; GO

    这将报告contactinfo表的磁盘使用情况信息。

    要同时对所有表使用此选项:

    1
    2
    3
    USE MyDatabase; GO

    sp_msforeachtable 'EXEC sp_spaceused [?]' GO

    您还可以从SQL Server的右键单击标准报告功能中获得磁盘使用情况。要获取此报表,请从对象资源管理器中的服务器对象导航,向下移动到数据库对象,然后右键单击任何数据库。从出现的菜单中,选择报告,然后选择标准报告,然后选择"磁盘使用情况(按分区):[databasename]"。


    这是另一种方法:使用SQL Server Management Studio,在对象资源管理器中,转到数据库并选择表。

    enter image description here

    然后打开对象资源管理器详细信息(按F7或转到"查看"->"对象资源管理器详细信息")。在"对象资源管理器详细信息"页中,右键单击列标题并启用希望在该页中看到的列。您也可以按任何列对数据进行排序。

    enter image description here


    经过一些搜索,我找不到一个简单的方法来获取所有表的信息。有一个名为sp_space used的简便存储过程,它将返回数据库使用的所有空间。如果提供表名,则返回该表使用的空间。但是,存储过程返回的结果不可排序,因为列是字符值。

    下面的脚本将生成我要查找的信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    create table #TableSize (
        Name varchar(255),
        [rows] int,
        reserved varchar(255),
        data varchar(255),
        index_size varchar(255),
        unused varchar(255))
    create table #ConvertedSizes (
        Name varchar(255),
        [rows] int,
        reservedKb int,
        dataKb int,
        reservedIndexSize int,
        reservedUnused int)

    EXEC sp_MSforeachtable @command1="insert into #TableSize
    EXEC sp_spaceused '?'"
    insert into #ConvertedSizes (Name, [rows], reservedKb, dataKb, reservedIndexSize, reservedUnused)
    select name, [rows],
    SUBSTRING(reserved, 0, LEN(reserved)-2),
    SUBSTRING(data, 0, LEN(data)-2),
    SUBSTRING(index_size, 0, LEN(index_size)-2),
    SUBSTRING(unused, 0, LEN(unused)-2)
    from #TableSize

    select * from #ConvertedSizes
    order by reservedKb desc

    drop table #TableSize
    drop table #ConvertedSizes


    1
     exec  sp_spaceused N'dbo.MyTable'

    对于所有表格,使用..(从保罗的评论中添加)

    1
    exec sp_MSForEachTable 'exec sp_spaceused [?]'


    上面的查询有助于查找表使用的空间量(包括索引),但如果要比较表上索引使用的空间量,请使用此查询:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    SELECT
        OBJECT_NAME(i.OBJECT_ID) AS TableName,
        i.name AS IndexName,
        i.index_id AS IndexID,
        8 * SUM(a.used_pages) AS 'Indexsize(KB)'
    FROM
        sys.indexes AS i JOIN
        sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id JOIN
        sys.allocation_units AS a ON a.container_id = p.partition_id
    where [i].[is_primary_key] = 0 -- fix for size discrepancy
    GROUP BY
        i.OBJECT_ID,
        i.index_id,
        i.name
    ORDER BY
        OBJECT_NAME(i.OBJECT_ID),
        i.index_id


    如果需要计算SSMS中"表属性-存储"页上的完全相同的数字,则需要使用与SSMS中相同的方法对其进行计数(适用于SQL Server 2005及更高版本…也适用于具有LOB字段的表-因为只计算"已用页面"并不能显示准确的索引大小):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    ;with cte as (
    SELECT
    t.name as TableName,
    SUM (s.used_page_count) as used_pages_count,
    SUM (CASE
                WHEN (i.index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)
                ELSE lob_used_page_count + row_overflow_used_page_count
            END) as pages
    FROM sys.dm_db_partition_stats  AS s
    JOIN sys.tables AS t ON s.object_id = t.object_id
    JOIN sys.indexes AS i ON i.[object_id] = t.[object_id] AND s.index_id = i.index_id
    GROUP BY t.name
    )
    select
        cte.TableName,
        cast((cte.pages * 8.)/1024 as decimal(10,3)) as TableSizeInMB,
        cast(((CASE WHEN cte.used_pages_count > cte.pages
                    THEN cte.used_pages_count - cte.pages
                    ELSE 0
              END) * 8./1024) as decimal(10,3)) as IndexSizeInMB
    from cte
    order by 2 desc

    我们使用表分区,由于记录重复,上面提供的查询有一些问题。

    对于需要这样做的人,您可以在下面找到在生成"磁盘使用情况(按表)"报告时由SQL Server 2014运行的查询。我认为它也适用于以前版本的SQL Server。

    它就像一个魅力。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    SELECT
        a2.name AS [tablename],
        a1.rows as row_count,
        (a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved,
        a1.data * 8 AS data,
        (CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,
        (CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused
    FROM
        (SELECT
            ps.object_id,
            SUM (
                CASE
                    WHEN (ps.index_id < 2) THEN row_count
                    ELSE 0
                END
                ) AS [rows],
            SUM (ps.reserved_page_count) AS reserved,
            SUM (
                CASE
                    WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                    ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
                END
                ) AS data,
            SUM (ps.used_page_count) AS used
        FROM sys.dm_db_partition_stats ps
            WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
        GROUP BY ps.object_id) AS a1
    LEFT OUTER JOIN
        (SELECT
            it.parent_id,
            SUM(ps.reserved_page_count) AS reserved,
            SUM(ps.used_page_count) AS used
         FROM sys.dm_db_partition_stats ps
         INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
         WHERE it.internal_type IN (202,204)
         GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
    INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id )
    INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
    WHERE a2.type <> N'S' and a2.type <> N'IT'
    ORDER BY a3.name, a2.name


    @xav answer的扩展,它处理表分区以获得以MB和GB为单位的大小。在SQL Server 2008/2012上测试(注释了一行,其中is_memory_optimized = 1)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    SELECT
        a2.name AS TableName,
        a1.rows as [RowCount],
        --(a1.reserved + ISNULL(a4.reserved,0)) * 8 AS ReservedSize_KB,
        --a1.data * 8 AS DataSize_KB,
        --(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS IndexSize_KB,
        --(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS UnusedSize_KB,
        CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_MB,
        CAST(ROUND(a1.data * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_MB,
        CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_MB,
        CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_MB,
        --'| |' Separator_MB_GB,
        CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_GB,
        CAST(ROUND(a1.data * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_GB,
        CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_GB,
        CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_GB
    FROM
        (SELECT
            ps.object_id,
            SUM (CASE WHEN (ps.index_id < 2) THEN row_count ELSE 0 END) AS [rows],
            SUM (ps.reserved_page_count) AS reserved,
            SUM (CASE
                    WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                    ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
                END
                ) AS data,
            SUM (ps.used_page_count) AS used
        FROM sys.dm_db_partition_stats ps
            --===Remove the following comment for SQL Server 2014+
            --WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
        GROUP BY ps.object_id) AS a1
    LEFT OUTER JOIN
        (SELECT
            it.parent_id,
            SUM(ps.reserved_page_count) AS reserved,
            SUM(ps.used_page_count) AS used
         FROM sys.dm_db_partition_stats ps
         INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
         WHERE it.internal_type IN (202,204)
         GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
    INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id )
    INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
    WHERE a2.type <> N'S' and a2.type <> N'IT'
    --AND a2.name = 'MyTable'       --Filter for specific table
    --ORDER BY a3.name, a2.name
    ORDER BY ReservedSize_MB DESC

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    -- Show the size of all the tables in a database sort by data size descending
    SET NOCOUNT ON
    DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
    DECLARE @cmd1 varchar(500)
    SET @cmd1 = 'exec sp_spaceused ''?'''

    INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
    EXEC sp_msforeachtable @command1=@cmd1

    SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC

    对mar_c答案的一个小改动,因为我经常回到这个页面,按大多数行的第一行排序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    SELECT
        t.NAME AS TableName,
        s.Name AS SchemaName,
        p.rows AS RowCounts,
        SUM(a.total_pages) * 8 AS TotalSpaceKB,
        SUM(a.used_pages) * 8 AS UsedSpaceKB,
        (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
    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
        --p.rows DESC --Uncomment to order by amount rows instead of size in KB.
        SUM(a.total_pages) DESC

    这将为您提供大小,并记录每个表的计数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    -- Get a list of tables and their sizes on disk
    ALTER PROCEDURE [dbo].[sp_Table_Sizes]
    AS
    BEGIN
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;
    DECLARE @table_name VARCHAR(500)  
    DECLARE @schema_name VARCHAR(500)  
    DECLARE @tab1 TABLE(
            tablename VARCHAR (500) collate database_default
           ,schemaname VARCHAR(500) collate database_default
    )

    CREATE TABLE #temp_Table (
            tablename sysname
           ,row_count INT
           ,reserved VARCHAR(50) collate database_default
           ,data VARCHAR(50) collate database_default
           ,index_size VARCHAR(50) collate database_default
           ,unused VARCHAR(50) collate database_default  
    )

    INSERT INTO @tab1  
    SELECT Table_Name, Table_Schema  
    FROM information_schema.tables  
    WHERE TABLE_TYPE = 'BASE TABLE'

    DECLARE c1 CURSOR FOR
    SELECT Table_Schema + '.' + Table_Name  
    FROM information_schema.tables t1  
    WHERE TABLE_TYPE = 'BASE TABLE'

    OPEN c1
    FETCH NEXT FROM c1 INTO @table_name
    WHILE @@FETCH_STATUS = 0  
    BEGIN  
            SET @table_name = REPLACE(@table_name, '[','');  
            SET @table_name = REPLACE(@table_name, '
    ]','');  

            -- make sure the object exists before calling sp_spacedused
            IF EXISTS(SELECT id FROM sysobjects WHERE id = OBJECT_ID(@table_name))
            BEGIN
                   INSERT INTO #temp_Table EXEC sp_spaceused @table_name, false;
            END

            FETCH NEXT FROM c1 INTO @table_name
    END
    CLOSE c1
    DEALLOCATE c1

    SELECT  t1.*
           ,t2.schemaname  
    FROM #temp_Table t1  
    INNER JOIN @tab1 t2 ON (t1.tablename = t2.tablename )
    ORDER BY schemaname,t1.tablename;

    DROP TABLE #temp_Table
    END


    对于在一个数据库中获取所有表大小,可以使用此查询:

    1
    Exec sys.sp_MSforeachtable ' sp_spaceused"?" '

    您可以将其更改为将所有结果插入临时表,然后从临时表中选择。

    1
    2
    Insert into #TempTable Exec sys.sp_MSforeachtable ' sp_spaceused"?" '
    Select * from #TempTable


    从使用osql的命令提示:

    1
    OSQL -E -d <*databasename*> -Q"exec sp_msforeachtable 'sp_spaceused [?]'"> result.txt

    以下步骤可以快速获取所有表格的大小:

  • 编写给定的T-SQL命令以列出所有数据库表:

    1
    select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
  • 现在复制数据库表列表,并将其复制到新的查询分析器窗口中

    1
    2
    3
    4
    5
    exec sp_spaceused table1
    exec sp_spaceused table2
    exec sp_spaceused table3
    exec sp_spaceused table4
    exec sp_spaceused table5
  • 在SQL查询分析器中,从顶部工具栏选项结果中选择到文件(ctrl+shift+f)。

  • 现在,最后点击上面工具栏上标记为红色的执行按钮。

  • 所有表的数据库大小现在存储在计算机上的一个文件中。

    Enter image description here


  • 我在马克的回答上又加了几列:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    with fs
    as
    (
    select i.object_id,
            p.rows AS RowCounts,
            SUM(a.total_pages) * 8 AS TotalSpaceKb
    from     sys.indexes i 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
        i.OBJECT_ID > 255
    GROUP BY
        i.object_id,
        p.rows
    )

    SELECT
        t.NAME AS TableName,
        fs.RowCounts,
        fs.TotalSpaceKb,
        t.create_date,
        t.modify_date,
        ( select COUNT(1)
            from sys.columns c
            where c.object_id = t.object_id ) TotalColumns    
    FROM
        sys.tables t INNER JOIN      
        fs  ON t.OBJECT_ID = fs.object_id
    WHERE
        t.NAME NOT LIKE 'dt%'
        AND t.is_ms_shipped = 0
    ORDER BY
        t.Name

    我的文章只与SQL Server 2000相关,并且已经过测试,可以在我的环境中工作。

    此代码访问单个实例的所有可能数据库,而不仅仅是单个数据库。

    我使用两个临时表来帮助收集适当的数据,然后将结果转储到一个"活动"表中。

    返回的数据是:databasename、databasetablename、rows(在表中)、data(表的大小,以KB为单位)、entry data(我发现这对于知道我上次运行脚本的时间很有用)。

    此代码的缺点是"data"字段不存储为int(字符"kb"保存在该字段中),这对于排序很有用(但并非完全必要)。

    希望这段代码可以帮助其他人,并为他们节省一些时间!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    CREATE PROCEDURE [dbo].[usp_getAllDBTableSizes]

    AS
    BEGIN
       SET NOCOUNT OFF

       CREATE TABLE #DatabaseTables([dbname] sysname,TableName sysname)
       CREATE TABLE #AllDatabaseTableSizes(Name sysname,[rows] VARCHAR(18), reserved VARCHAR(18), data VARCHAR(18), index_size VARCHAR(18), unused VARCHAR(18))

       DECLARE @SQL nvarchar(4000)
       SET @SQL='select ''?'' AS [Database], Table_Name from [?].information_schema.tables WHERE TABLE_TYPE = ''BASE TABLE'' '

       INSERT INTO #DatabaseTables(DbName, TableName)
          EXECUTE sp_msforeachdb @Command1=@SQL

       DECLARE AllDatabaseTables CURSOR LOCAL READ_ONLY FOR  
       SELECT TableName FROM #DatabaseTables

       DECLARE AllDatabaseNames CURSOR LOCAL READ_ONLY FOR  
       SELECT DBName FROM #DatabaseTables

       DECLARE @DBName sysname  
       OPEN AllDatabaseNames  

       DECLARE @TName sysname
       OPEN AllDatabaseTables  

       WHILE 1=1 BEGIN
          FETCH NEXT FROM AllDatabaseNames INTO @DBName  
          FETCH NEXT FROM AllDatabaseTables INTO @TName
          IF @@FETCH_STATUS<>0 BREAK  
          INSERT INTO #AllDatabaseTableSizes
             EXEC ( 'EXEC ' + @DBName + '.dbo.sp_spaceused ' + @TName)

       END

       --http://msdn.microsoft.com/en-us/library/aa175920(v=sql.80).aspx
       INSERT INTO rsp_DatabaseTableSizes (DatabaseName, name, [rows], data)
          SELECT   [dbname], name, [rows],  data FROM #DatabaseTables
          INNER JOIN #AllDatabaseTableSizes
          ON #DatabaseTables.TableName = #AllDatabaseTableSizes.Name
          GROUP BY [dbname] , name, [rows],  data
          ORDER BY [dbname]
       --To be honest, I have no idea what exact duplicates we are dropping
        -- but in my case a near enough approach has been good enough.
       DELETE FROM [rsp_DatabaseTableSizes]
       WHERE name IN
          (
          SELECT name
          FROM [rsp_DatabaseTableSizes]
          GROUP BY name
          HAVING COUNT(*) > 1
          )

       DROP TABLE #DatabaseTables
       DROP TABLE #AllDatabaseTableSizes

       CLOSE AllDatabaseTables  
       DEALLOCATE AllDatabaseTables  

       CLOSE AllDatabaseNames  
       DEALLOCATE AllDatabaseNames      
    END

    --EXEC [dbo].[usp_getAllDBTableSizes]

    如果您需要知道,rsp_databasetablesizes表是通过以下方式创建的:

    1
    2
    3
    4
    5
    6
    7
    CREATE TABLE [dbo].[rsp_DatabaseSizes](
        [DatabaseName] [varchar](1000) NULL,
        [dbSize] [decimal](15, 2) NULL,
        [DateUpdated] [smalldatetime] NULL
    ) ON [PRIMARY]

    GO

    作为对Marc_答案(已被接受的答案)的简单扩展,将其调整为返回列计数并允许过滤:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    SELECT *
    FROM
    (

    SELECT
        t.NAME AS TableName,
        s.Name AS SchemaName,
        p.rows AS RowCounts,
        COUNT(DISTINCT c.COLUMN_NAME) as ColumnCount,
        SUM(a.total_pages) * 8 AS TotalSpaceKB,
        (SUM(a.used_pages) * 8) AS UsedSpaceKB,
        (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
    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
        INFORMATION_SCHEMA.COLUMNS c ON t.NAME = c.TABLE_NAME
    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
    ) AS Result

    WHERE
        RowCounts > 1000
        AND ColumnCount > 10
    ORDER BY
        UsedSpaceKB DESC


    在上面的@mark answer上搜索,添加了@updateusage='true'以强制使用最新的大小统计信息(https://msdn.microsoft.com/en-us/library/ms188776.aspx):

    1
    2
    3
    4
    5
    6
    7
    8
            SET NOCOUNT ON
            DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
            DECLARE @cmd1 varchar(500)
            SET @cmd1 = 'exec sp_spaceused @objname =''?'', @updateusage =''true'' '

            INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
            EXEC sp_msforeachtable @command1=@cmd1
    SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC