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

是否有一种简单的方法来确定每个表占用的磁盘空间?


当前回答

对于Azure,我使用了:

您应该有SSMS v17.x+

我使用;

正如用户Sparrow所提到的:

打开数据库>并选择表,然后按F7键你应该看到行数作为:

此处的SSMS连接到Azure数据库

其他回答

下面是另一种方法:使用SQLServerManagementStudio,在对象资源管理器中,转到数据库并选择表

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

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

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

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

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

这段代码的缺点是“data”字段不是以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

扩展到@xav答案,处理表分区以获得MB和GB大小。在SQL Server 2008/2012上测试(注释了一行,其中is_memory_optized=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

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

编写给定的T-SQL命令以列出所有数据库表:从INFORMATION_SCHEMA.TABLES中选择“exec sp_spaceused”+TABLE_NAME,其中TABLE_TYPE=“BASE TABLE”现在复制数据库表列表,并将其复制到新的查询分析器窗口中执行sp_spaceused表1执行sp_spaceused表2执行sp_spaceused表3执行sp_spaceused表4执行sp_spaceused表5在SQL查询分析器中,从顶部工具栏中选择“结果到文件”选项(Ctrl+Shift+F)。现在,最后点击上面工具栏中标记为红色的Execute按钮。所有表的数据库大小现在存储在计算机上的文件中。

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

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