【问题标题】:Get size of all tables in database获取数据库中所有表的大小
【发布时间】:2011-12-15 02:15:11
【问题描述】:

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

有没有一种简单的方法可以确定每个表占用了多少磁盘空间?

【问题讨论】:

标签: sql-server tsql


【解决方案1】:
CREATE TABLE #tmp_table_info
(
id int identity(1,1),
tblname varchar(200)
);
CREATE TABLE #SpaceUsed 
(
     TableName sysname
    ,NumRows BIGINT
    ,ReservedSpace VARCHAR(50)
    ,DataSpace VARCHAR(50)
    ,IndexSize VARCHAR(50)
    ,UnusedSpace VARCHAR(50)
) 

insert into #tmp_table_info
select s.name+'.'+t.name 
from sys.tables t 
inner join sys.schemas s on t.schema_id = s.schema_id
where t.type = 'U';

declare @min int =1,@max int = 0
select @max = count(*)
from #tmp_table_info
while(@min<=@max)
begin
    declare @tablename varchar(200)
    select @tablename=tblname
    from #tmp_table_info
    where id =@min

    DECLARE @str VARCHAR(500)
    SET @str =  'sp_spaceused '''+@tablename+''''
    INSERT INTO #SpaceUsed 
    EXEC (@str)  
    set @min =@min + 1
end;
select @@SERVERNAME as servername,DB_NAME() as DatabaseName,CONVERT(numeric(18,0),REPLACE(ReservedSpace,' KB','')) / 1024 as ReservedSpace_MB,
CONVERT(numeric(18,0),REPLACE(DataSpace,' KB','')) / 1024 as DataSpace_MB,
CONVERT(numeric(18,0),REPLACE(IndexSize,' KB','')) / 1024 as IndexSpace_MB,
CONVERT(numeric(18,0),REPLACE(UnusedSpace,' KB','')) / 1024 as UnusedSpace_MB from #SpaceUsed
drop table #tmp_table_info
drop table #SpaceUsed

【讨论】:

    【解决方案2】:

    当前接受的答案有超过 2600 个赞成票,但在使用多个分区和/或过滤索引时会给出不正确的结果。它也不区分数据和索引的大小,这通常非常相关。一些建议的修复没有解决核心问题,或者根本就是错误的。

    以下查询解决了所有这些问题。

    SELECT 
         [object_id]        = t.[object_id]
        ,[schema_name]      = s.[name]
        ,[table_name]       = t.[name]
        ,[index_name]       = CASE WHEN i.[type] in (0,1,5) THEN null    ELSE i.[name] END -- 0=Heap; 1=Clustered; 5=Clustered Columnstore
        ,[object_type]      = CASE WHEN i.[type] in (0,1,5) THEN 'TABLE' ELSE 'INDEX'  END
        ,[index_type]       = i.[type_desc]
        ,[partition_count]  = p.partition_count
        ,[row_count]        = p.[rows]
        ,[data_compression] = CASE WHEN p.data_compression_cnt > 1 THEN 'Mixed'
                                   ELSE (  SELECT DISTINCT p.data_compression_desc
                                           FROM sys.partitions p
                                           WHERE i.[object_id] = p.[object_id] AND i.index_id = p.index_id
                                        )
                              END
        ,[total_space_MB]   = cast(round(( au.total_pages                  * (8/1024.00)), 2) AS DECIMAL(36,2))
        ,[used_space_MB]    = cast(round(( au.used_pages                   * (8/1024.00)), 2) AS DECIMAL(36,2))
        ,[unused_space_MB]  = cast(round(((au.total_pages - au.used_pages) * (8/1024.00)), 2) AS DECIMAL(36,2))
    FROM sys.schemas s
    JOIN sys.tables  t ON s.schema_id = t.schema_id
    JOIN sys.indexes i ON t.object_id = i.object_id
    JOIN (
        SELECT [object_id], index_id, partition_count=count(*), [rows]=sum([rows]), data_compression_cnt=count(distinct [data_compression])
        FROM sys.partitions
        GROUP BY [object_id], [index_id]
    ) p ON i.[object_id] = p.[object_id] AND i.[index_id] = p.[index_id]
    JOIN (
        SELECT p.[object_id], p.[index_id], total_pages = sum(a.total_pages), used_pages = sum(a.used_pages), data_pages=sum(a.data_pages)
        FROM sys.partitions p
        JOIN sys.allocation_units a ON p.[partition_id] = a.[container_id]
        GROUP BY p.[object_id], p.[index_id]
    ) au ON i.[object_id] = au.[object_id] AND i.[index_id] = au.[index_id]
    WHERE t.is_ms_shipped = 0 -- Not a system table
    

    【讨论】:

      【解决方案3】:

      对于 Azure,我使用了这个:

      您应该拥有 SSMS v17.x+

      我用过;

      有了这个,作为用户Sparrow has mentioned

      打开您的Databases> 并选择表格
      然后按F7键 你应该看到row count
      作为:

      SSMS 此处已连接到 Azure 数据库

      【讨论】:

      • F7 的使用严重不足。
      • 内存优化表有问题,(我刚看到这个帖子后测试:)
      • 右键单击列以显示其他属性,例如索引空间或使用的数据空间。
      【解决方案4】:

      如果您只关心数据库中浪费的空白空间而不关心单个表,则可以考虑以下事项:

      如果数据库经历大量数据插入然后删除,可能就像在 ETL 情况下,这将导致数据库中过多的未使用空间,因为文件组 自动增长 但从不自动- 收缩。

      您可以使用数据库的属性页面查看是否是这种情况。您可以缩小(右键单击数据库 > 任务 > 缩小)并收回一些空间。但是,如果根本原因仍然存在,那么数据库将会重新增长(并且会花费额外的时间来尝试重新增长,并且事情会变慢,直到增长足够多 - 所以在这种情况下不要这样做)

      【讨论】:

        【解决方案5】:

        我发现此查询易于使用且快速。

        select schema_name(tab.schema_id) + '.' + tab.name as [table], 
        cast(sum(spc.used_pages * 8)/1024.00 as numeric(36, 2)) as used_mb,
        cast(sum(spc.total_pages * 8)/1024.00 as numeric(36, 2)) as allocated_mb
        from sys.tables (nolock) tab
        inner join sys.indexes (nolock) ind 
            on tab.object_id = ind.object_id
        inner join sys.partitions  (nolock) part 
            on ind.object_id = part.object_id and ind.index_id = part.index_id
        inner join sys.allocation_units (nolock) spc
            on part.partition_id = spc.container_id
        group by schema_name(tab.schema_id) + '.' + tab.name
        order by sum(spc.used_pages) desc
        

        【讨论】:

          【解决方案6】:

          以上查询对于查找表使用的空间量(包括索引)非常有用,但如果您想比较表上的索引使用了多少空间,请使用以下查询:

          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
          

          【讨论】:

          • 特定表的 Indexsize(KB) 列的总和与 sp_spaceused 中的 index_size 不一致的原因是什么?
          • @Derek 通过添加where [i].[is_primary_key] = 0 修正了他的答案。现在大小应该匹配了。
          • 谢谢,但这实际上也行不通。我有一个(非常小的)测试数据库,感兴趣的表有两个索引——一个列上的主聚集索引和其他两列上的非聚集索引。这个查询说他们每个人都使用 16kB,但 sp_spaceused 说总索引使用量是 24kB。我的部分困惑是:将此查询与已接受答案的“UsedSpaceKB”进行比较,我看不出有真正的区别。相同的连接,只是缺少 sys.tables 的添加。我错过了什么,还是这个查询本身就被破坏了?
          • 我有大型数据库。尺寸与sp_spaceused 匹配。我测量 GB,所以几兆不匹配并不多。我不在乎确切的尺寸,只是一个想法。
          【解决方案7】:
          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
          

          【讨论】:

          • 愚蠢的问题,但是这个查询有没有可能导致行锁定?
          • 索引也使用空间,索引使用的空间量可以通过下面的query 找到。
          • 您的脚本在过滤索引方面存在问题:对于给定表的每个过滤索引,我在结果中看到一个带有该表名称的额外行。这些额外行中的每一行的“RowCounts”对应于过滤索引之一覆盖的行数。 (在 Sql2012 上)
          • @Todd:有些人希望以这种方式排序 - 其他人希望按表名排序 - 随你选择,根据需要调整代码 ....
          • 如果您的表是分区的,它们会出现多次,而没有任何迹象表明正在发生什么。您可以将 p.partition_number 添加到选择列表中,也可以 SUM(p.Rows) 并将其从 group by 中删除。
          【解决方案8】:

          Mar_c's answer 的一个小改动,因为我经常回到这个页面,按大多数行的第一个排序:

          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 
          

          【讨论】:

            【解决方案9】:

            作为marc_s's answer(已被接受的那个)的一个简单扩展,它被调整为返回列数并允许过滤:

            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
            

            【讨论】:

            • 加入 Columns 表后,您不再拥有正确的表空间。外部应用将是解决方法。
            【解决方案10】:

            这是一个示例查询,用于获取按大小降序排列的大于 1GB 的表。

            USE YourDB
            GO
            
            DECLARE @Mult float = 8
            SET @Mult = @Mult / POWER(2, 20) -- Use POWER(2, 10) for MBs
            
            ; WITH CTE AS
            (
            SELECT
                i.object_id,
                Rows = MAX(p.rows),
                TotalSpaceGB = ROUND(SUM(a.total_pages) * @Mult, 0),
                UsedSpaceGB = ROUND(SUM(a.used_pages) * @Mult, 0)
            FROM 
                sys.indexes i
            JOIN
                sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
            JOIN
                sys.allocation_units a ON p.partition_id = a.container_id
            WHERE
                i.object_id > 255
            GROUP BY
                i.object_id
            HAVING
                SUM(a.total_pages) * @Mult > 1
            )
            SELECT 
                SchemaName = s.name,
                TableName = t.name,
                c.TotalSpaceGB,
                c.UsedSpaceGB,
                UnusedSpaceGB = c.TotalSpaceGB - c.UsedSpaceGB,
                [RowCount] = c.Rows
            FROM 
                CTE c
            JOIN    
                sys.tables t ON t.object_id = c.object_id
            JOIN
                sys.schemas s ON t.schema_id = s.schema_id
            ORDER BY
                c.TotalSpaceGB DESC
            

            【讨论】:

              【解决方案11】:

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

              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
              

              【讨论】:

                【解决方案12】:

                这是另一种方法:使用 SQL Server Management Studio,在 Object Explorer 中,转到您的数据库并选择 Tables

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

                【讨论】:

                • @batmaci 当您对 Azure SQL 数据库发表评论时,不确定这是否有效,但在最新版本的 SSMS 中,它似乎至少部分有效。对我来说,似乎对表元数据的查询正在超时,但在此之前它似乎返回了几张(3-10)张有价值的表,包括(可靠地)选定的表。选择一个表格,如果没有显示,点击刷新可以看到你想要的表格。
                • 我在 Azure 中使用了 this,谢谢(加一个),
                • 您还可以使用 NirSoft SysExporter 等实用程序将列表导出为 CSV 文件:nirsoft.net/utils/sysexp.html
                【解决方案13】:

                这是一种通过以下步骤快速获取所有表格大小的方法:

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

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

                  exec sp_spaceused table1
                  exec sp_spaceused table2
                  exec sp_spaceused table3
                  exec sp_spaceused table4
                  exec sp_spaceused table5
                  
                3. 在 SQL 查询分析器中,从顶部工具栏选项中选择Results to file (Ctrl + Shift kbd> + F)。

                4. 现在终于点击了上面工具栏上标记为红色的执行按钮。

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

                【讨论】:

                  【解决方案14】:
                   exec  sp_spaceused N'dbo.MyTable'
                  

                  对于所有表格,使用..(来自 Paul 的 cmets)

                  exec sp_MSForEachTable 'exec sp_spaceused [?]'
                  

                  【讨论】:

                  • 偷偷摸摸 - 你从exec sp_helpdb 更改为 显示有关表格的任何内容,更改为exec sp_spaceused 显示 - 但仅适用于一个一次一个表...它不会让您概览您拥有哪些表、它们有多少行以及它们占用了多少空间。
                  • exec sp_MSForEachTable 'exec sp_spaceused [?]'
                  【解决方案15】:

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

                  1. 右键单击数据库
                  2. 导航到报告 > 标准报告 > 磁盘使用情况(按表)

                  注意:数据库兼容级别必须设置为 90 或更高才能正常工作。见http://msdn.microsoft.com/en-gb/library/bb510680.aspx

                  【讨论】:

                  • 在 Management Studio 2012 中,您可以执行以下操作:查看对象资源管理器详细信息 (F7) 并导航到对象资源管理器中的“表”。在详细信息中右键单击标题并选择大小列。
                  • 用于建议 SSMS 2012 的新功能。对于我们这些老家伙来说,我们从来没有提供过此功能。所以我们只是用旧的 TSQL 方式来做 :)
                  • 信不信由你,有时只是凡人(开发人员)希望看到此信息,我们无权使用内置报告,但我们可以在接受的答案中运行 TSQL。 :) 仅供参考(顺便说一句,我仍然赞成你的回答)
                  • Azure SQL 中似乎不存在 :-(
                  • 我知道这并不严重,但是,请您将边缘化群体从工程和技术领域推开,这种推理无处不在。你应该两者都学,但你也不应该责备人们使用节省时间的实用程序来更智能、更快地工作。 (虽然 SSMS 有时似乎是一个“减慢实用程序”......:X)个人而言,表格数据的读数在 GUI 中通常更清晰,尽管 Microsoft 构建的工具往往是所有与 UI 相关的例外。
                  【解决方案16】:

                  从命令提示符使用OSQL:

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

                  【讨论】:

                    【解决方案17】:

                    我们使用表分区,但由于重复记录,我们在上面提供的查询中遇到了一些问题。

                    对于需要此功能的用户,您可以在生成“按表的磁盘使用情况”报告时在 SQL Server 2014 运行的查询下方找到。我认为它也适用于以前版本的 SQL Server。

                    它就像一个魅力。

                    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
                    

                    【讨论】:

                      【解决方案18】:

                      在上面的@Mark 答案上重复,添加了@updateusage='true' 以强制使用最新的尺寸统计信息(https://msdn.microsoft.com/en-us/library/ms188776.aspx):

                              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
                      

                      【讨论】:

                        【解决方案19】:

                        要获取一个数据库中的所有表大小,您可以使用此查询:

                        Exec sys.sp_MSforeachtable ' sp_spaceused "?" '
                        

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

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

                        【讨论】:

                          【解决方案20】:

                          如果您需要在 SSMS 中的“表属性 - 存储”页面上计算完全相同的数字,则需要使用与 SSMS 中相同的方法来计算它们(适用于 sql server 2005 及更高版本.. . 并且也适用于具有 LOB 字段的表 - 因为仅计算“used_pa​​ges”不足以显示准确的索引大小):

                          ;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
                          

                          【讨论】:

                          • 你能详细说明为什么WHEN (i.index_id &lt; 2|) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count) 给出堆的页数吗?在sql server 2014 中只有一个索引满足此条件(并且该索引是主键:i.index_id = 1)。但是,如果我将大小与 sb_spaceused 的结果进行比较,那么它们匹配(在很大程度上)
                          【解决方案21】:
                          -- 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
                          

                          【讨论】:

                            【解决方案22】:

                            我在 marc_s 答案的顶部添加了几列:

                            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
                            

                            【讨论】:

                              【解决方案23】:

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

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

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

                              返回的数据是:DatabaseName、DatabaseTableName、Rows(在表中)、data(表的大小以 KB 为单位)、条目数据(我发现这有助于了解我上次运行脚本的时间)。

                              此代码的缺点是“数据”字段未存储为 int(字符“KB”保存在该字段中),这对于排序很有用(但并非完全必要)。

                              希望这段代码可以帮助那里的人并节省他们一些时间!

                              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 表是通过以下方式创建的:

                              CREATE TABLE [dbo].[rsp_DatabaseSizes](
                                  [DatabaseName] [varchar](1000) NULL,
                                  [dbSize] [decimal](15, 2) NULL,
                                  [DateUpdated] [smalldatetime] NULL
                              ) ON [PRIMARY]
                              
                              GO
                              

                              【讨论】:

                                【解决方案24】:

                                sp_spaceused 可以获得有关表、索引视图或整个数据库使用的磁盘空间的信息。

                                例如:

                                USE MyDatabase; GO
                                
                                EXEC sp_spaceused N'User.ContactInfo'; GO
                                

                                这会报告 ContactInfo 表的磁盘使用信息。

                                一次对所有表使用它:

                                USE MyDatabase; GO
                                
                                sp_msforeachtable 'EXEC sp_spaceused [?]' GO
                                

                                您还可以从 SQL Server 的右键单击标准报告功能中获取磁盘使用情况。要访问此报告,请从对象资源管理器中的服务器对象导航,向下移动到数据库对象,然后右键单击任何数据库。从出现的菜单中,选择 Reports,然后选择 Standard Reports,然后选择“Disk Usage by Partition: [DatabaseName]”。

                                【讨论】:

                                • 虽然在 SSMS 中使用sp_msforeachtable 很容易触发System.OutOfMemoryException,但如果您有大量表,这很简洁,因此使用临时表存储可能是一个更好的主意结果。
                                • 我可以看到 sp_spacedused 的主要问题是它似乎以人类可读的格式返回数据(例如,在我的情况下,在“保留”列中它有“152 KB”)。我认为这将酌情切换到 MB/GB。这在很多情况下显然很有用,但如果您需要根据大小应用一些逻辑,或者想要比较值或其他什么,则不是。我正在寻找一种关闭它的方法,但我找不到(我使用的是 SQL Server 2005 :()
                                【解决方案25】:

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

                                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
                                

                                【讨论】:

                                • 如果您发布代码、XML 或数据示例,在文本编辑器中突出显示这些行,然后单击编辑器上的“代码示例”按钮 ({ })工具栏以很好地格式化和语法突出显示它!
                                【解决方案26】:

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

                                以下脚本将生成我正在寻找的信息。

                                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
                                

                                【讨论】:

                                  猜你喜欢
                                  • 2018-09-15
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2018-02-24
                                  • 1970-01-01
                                  • 2021-04-05
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多