【问题标题】:Table and Index size in SQL ServerSQL Server 中的表和索引大小
【发布时间】:2010-09-23 22:17:26
【问题描述】:

我们能否有一个 SQL 查询,它基本上有助于查看 SQl Server 中的表和索引大小。

SQL 服务器如何维护表/索引的内存使用情况?

【问题讨论】:

  • 你可能还会发现存储过程sp_helpdb很有用
  • 这个已经有答案了,但是我个人使用这个链接中的查询:qualityofdata.com/2011/02/02/…

标签: sql-server


【解决方案1】:

sp_spaceused 为您提供所有索引组合的大小。

如果您想要一个表的每个索引的大小,请使用以下两个查询之一:

SELECT
    i.name                  AS IndexName,
    SUM(s.used_page_count) * 8   AS IndexSizeKB
FROM sys.dm_db_partition_stats  AS s 
JOIN sys.indexes                AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
WHERE s.[object_id] = object_id('dbo.TableName')
GROUP BY i.name
ORDER BY i.name

SELECT
    i.name              AS IndexName,
    SUM(page_count * 8) AS IndexSizeKB
FROM sys.dm_db_index_physical_stats(
    db_id(), object_id('dbo.TableName'), NULL, NULL, 'DETAILED') AS s
JOIN sys.indexes AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
GROUP BY i.name
ORDER BY i.name

结果通常略有不同,但在 1% 以内。

【讨论】:

  • 第一个查询包含主键,由于几个原因,这有点令人困惑。
  • 第二个查询向我抛出Msg 102, Level 15, State 1, Line 5 - Incorrect syntax near '('.,但我看不出语法有任何问题。有什么想法吗?
  • 奥利弗,你运行的是什么版本?它在 2008R2 和 2012 年对我来说按原样工作。
【解决方案2】:

不带参数的exec sp_spaceused 显示整个数据库的摘要。 foreachtable 解决方案为每个表生成一个结果集 - 如果表太多,SSMS 可能无法处理。

我创建了一个script,它通过sp_spaceused 收集表信息,并在单个记录集中显示摘要,按大小排序。

create table #t
(
  name nvarchar(128),
  rows varchar(50),
  reserved varchar(50),
  data varchar(50),
  index_size varchar(50),
  unused varchar(50)
)

declare @id nvarchar(128)
declare c cursor for
select '[' + sc.name + '].[' + s.name + ']' FROM sysobjects s INNER JOIN sys.schemas sc ON s.uid = sc.schema_id where s.xtype='U'

open c
fetch c into @id

while @@fetch_status = 0 begin

  insert into #t
  exec sp_spaceused @id

  fetch c into @id
end

close c
deallocate c

select * from #t
order by convert(int, substring(data, 1, len(data)-3)) desc

drop table #t

【讨论】:

  • 您的脚本仅处理架构“dbo”中的表。如果我的数据库中有一个架构为“Audit”的表,则需要像这样调用 sp_spaceused:exec sp_spaceused 'Audit.Data'。因此,需要修改脚本以向其提供以模式名称开头的表名(用点分隔),以便它从其他模式返回有关表的数据。
  • 好点@Boadad ...这应该是一个超级容易解决的问题。用这个替换“select name from sysobjects where xtype='U'”应该可以解决问题:“select '[' + sc.name + '].[' + s.name + ']' FROM sysobjects s INNER JOIN sys .schemas sc ON s.uid = sc.schema_id where s.xtype='U'" 很棒的脚本,谢谢!
  • 可以不使用临时表将数据插入到其他非临时表中吗?
  • @PrabhakarPandey 当然只是删除#
【解决方案3】:

在 SQL 2012 上,在表级别获取此信息变得非常简单:

SQL Management Studio -> 右击 Db -> Reports -> Standard Reports -> Disk Usage by table!

享受

【讨论】:

    【解决方案4】:
    EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"
    

    【讨论】:

    • 如果您发布代码、XML 或数据示例,在文本编辑器中突出显示这些行,然后单击编辑器上的“代码示例”按钮 ({ })工具栏以很好地格式化和语法突出显示它!
    【解决方案5】:
    --Gets the size of each index for the specified table
    DECLARE @TableName sysname = N'SomeTable';
    
    SELECT i.name AS IndexName
          ,8 * SUM(s.used_page_count) AS IndexSizeKB
    FROM sys.indexes AS i
        INNER JOIN sys.dm_db_partition_stats AS s 
            ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id
    WHERE s.[object_id] = OBJECT_ID(@TableName, N'U')
    GROUP BY i.name
    ORDER BY i.name;
    
    SELECT i.name AS IndexName
          ,8 * SUM(a.used_pages) AS IndexSizeKB
    FROM sys.indexes AS i
        INNER JOIN sys.partitions AS p 
            ON i.[object_id]  = p.[object_id] AND i.index_id = p.index_id
        INNER JOIN sys.allocation_units AS a 
            ON p.partition_id = a.container_id
    WHERE i.[object_id] = OBJECT_ID(@TableName, N'U')
    GROUP BY i.name
    ORDER BY i.name;
    

    【讨论】:

      【解决方案6】:

      自从创建这篇文章以来已经很长时间了,但我想分享我的脚本:

      WITH CteIndex
      AS
      (
      SELECT 
           reservedpages = (reserved_page_count)
           ,usedpages = (used_page_count)
           ,pages = (
                  CASE
                      WHEN (s.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
                  )    
           ,s.object_id   
           ,i.index_id        
           ,i.type_desc AS IndexType
           ,i.name AS indexname
          FROM sys.dm_db_partition_stats s
          INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id   
      )
      SELECT DISTINCT
      DB_NAME(DB_ID()) AS DatabaseName
      ,o.name AS TableName
      ,o.object_id
      ,ct.indexname
      ,ct.IndexType
      ,ct.index_id
      , IndexSpace = LTRIM (STR ((CASE WHEN usedpages > pages THEN CASE WHEN ct.index_id < 2 THEN  pages ELSE (usedpages - pages) END ELSE 0 END) * 8, 15, 0) + ' KB')
      FROM CteIndex ct
      INNER JOIN sys.objects o ON o.object_id = ct.object_id
      INNER JOIN sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL , NULL) ps ON ps.object_id = o.object_id
      AND ps.index_id = ct.index_id
      ORDER BY name ASC
      

      这适用于:

      • SQL Server(从 2008 年开始)
      • 包括每个当前数据库的所有表的信息

      【讨论】:

      • 这很棒。我所做的一项更改是对IndexSpace 列进行更改,以使其保持数字化,以便按大小排序,如下所示:, IndexSpaceKB = (CASE WHEN usedpages &gt; pages THEN CASE WHEN ct.index_id &lt; 2 THEN pages ELSE (usedpages - pages) END ELSE 0 END) * 8
      【解决方案7】:

      这是最成功答案的更紧凑版本:

      create table #tbl(
        name nvarchar(128),
        rows varchar(50),
        reserved varchar(50),
        data varchar(50),
        index_size varchar(50),
        unused varchar(50)
      )
      
      exec sp_msforeachtable 'insert into #tbl exec sp_spaceused [?]'
      
      select * from #tbl
          order by convert(int, substring(data, 1, len(data)-3)) desc
      
      drop table #tbl
      

      【讨论】:

        【解决方案8】:

        有一个扩展存储过程sp_spaceused 可以获取此信息。从数据字典中执行此操作相当复杂,但This link 扇出执行此操作的脚本。 This stackoverflow question 提供了一些关于底层数据结构的信息,您可以使用这些信息为容量规划构建表和索引大小的估计值。

        【讨论】:

          【解决方案9】:

          这个查询来自另外两个答案:

          Get size of all tables in database

          How to find largest objects in a SQL Server database?

          ,但我将其增强为通用。它使用sys.objects 字典:

          SELECT 
              s.NAME as SCHEMA_NAME,
              t.NAME AS OBJ_NAME,
              t.type_desc as OBJ_TYPE,
              i.name as indexName,
              sum(p.rows) as RowCounts,
              sum(a.total_pages) as TotalPages, 
              sum(a.used_pages) as UsedPages, 
              sum(a.data_pages) as DataPages,
              (sum(a.total_pages) * 8) / 1024 as TotalSpaceMB, 
              (sum(a.used_pages) * 8) / 1024 as UsedSpaceMB, 
              (sum(a.data_pages) * 8) / 1024 as DataSpaceMB
          FROM 
              sys.objects t
          INNER JOIN
              sys.schemas s ON t.SCHEMA_ID = s.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
              i.OBJECT_ID > 255 AND   
              i.index_id <= 1
          GROUP BY 
              s.NAME, t.NAME, t.type_desc, i.object_id, i.index_id, i.name 
          ORDER BY
              sum(a.total_pages) DESC
          ;
          

          【讨论】:

            【解决方案10】:

            查看单个表(及其索引)的存储数据:

            exec sp_spaceused MyTable
            

            【讨论】:

              猜你喜欢
              • 2013-03-31
              • 1970-01-01
              • 2010-09-22
              • 1970-01-01
              • 1970-01-01
              • 2010-09-15
              • 2014-10-04
              • 2019-09-27
              • 2011-08-28
              相关资源
              最近更新 更多