获取数据库中所有表的大小
我已经inheritance了一个相当大的SQL Server数据库。 考虑到它包含的数据,它似乎占用了比我预期更多的空间。
有没有一种简单的方法来确定每个表上的磁盘空间消耗多less?
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_spaceused可以获取有关表,索引视图或整个数据库使用的磁盘空间的信息。
例如:
USE MyDatabase; GO EXEC sp_spaceused N'User.ContactInfo'; GO
这将报告ContactInfo表的磁盘使用情况信息。
要一次使用所有表格:
USE MyDatabase; GO sp_msforeachtable 'EXEC sp_spaceused [?]' GO
您还可以从SQL Server的右键单击标准报告function中获取磁盘使用情况。 要获取此报告,请从对象资源pipe理器中的服务器对象导航,向下移至“数据库”对象,然后右键单击任何数据库。 从出现的菜单中,select“报告”,然后select“标准报告”,然后select“分区的磁盘使用情况:[数据库名称]”。
经过一番search,我找不到一个简单的方法来获取所有表的信息。 有一个名为sp_spaceused的方便的存储过程,将返回数据库使用的所有空间。 如果提供了表名,则返回该表使用的空间。 但是,存储过程返回的结果不可sorting,因为列是字符值。
以下脚本将生成我正在查找的信息。
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
exec sp_spaceused N'dbo.MyTable'
对于所有的表,使用..(从保罗的评论中join)
exec sp_MSForEachTable 'exec sp_spaceused [?]'
以上查询对于查找表(包含索引)使用的空间量非常有用,但是如果要比较表上索引使用多less空间,请使用以下查询:
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 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字段的表格正确工作 – 因为只计算“used_pages”不足以显示准确的索引大小):
;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
-- 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
这将给你的大小,并logging每个表的计数。
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
Mar_c的回答发生了一个小小的变化,因为我经常回到这个页面,大多数排在第一位:
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
为了获得一个数据库中的所有表大小,你可以使用这个查询:
Exec sys.sp_MSforeachtable ' sp_spaceused "?" '
您可以将其更改为将所有结果插入到临时表中,然后从临时表中select。
Insert into #TempTable Exec sys.sp_MSforeachtable ' sp_spaceused "?" ' Select * from #TempTable
我在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
我们使用表分区,并且由于重复的logging,在上面提供的查询中遇到了一些麻烦。
对于那些需要此function的用户,在生成“磁盘使用情况表”报告时,可以在SQL Server 2014运行的查询下方find该查询。 我假设它也适用于以前版本的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
我的文章只与SQL Server 2000相关,并且已经过testing,可以在我的环境中工作。
此代码访问单个实例的所有可能数据库 ,而不仅仅是一个数据库。
我使用两个临时表来帮助收集适当的数据,然后将结果转储到一个“Live”表中。
返回的数据是:DatabaseName,DatabaseTableName,行(在表中),数据(KB的大小看起来像表),条目数据(我发现这有助于知道我上次运行脚本)。
这个代码的缺点是'数据'字段没有存储为int(string'KB'保存在该字段中),这对于sorting很有用(但不是完全必要的)。
希望这段代码可以帮助那里的人,为他们节省一些时间!
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表是通过以下方式创build的:
CREATE TABLE [dbo].[rsp_DatabaseSizes]( [DatabaseName] [varchar](1000) NULL, [dbSize] [decimal](15, 2) NULL, [DateUpdated] [smalldatetime] NULL ) ON [PRIMARY] GO
在使用OSQL的命令提示符下:
OSQL -E -d <*databasename*> -Q "exec sp_msforeachtable 'sp_spaceused [?]'" > result.txt
作为marc_s的答案(被接受的答案)的一个简单的扩展,这被调整为返回列数并允许过滤:
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
以下是通过以下步骤快速获取所有表格大小的方法:
-
编写给定的T-SQL命令来列出所有数据库表:
select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
-
现在复制数据库表的列表,并将其复制到新的查询分析器窗口中
exec sp_spaceused table1 exec sp_spaceused table2 exec sp_spaceused table3 exec sp_spaceused table4 exec sp_spaceused table5
-
在SQL 查询分析器中 ,从顶部工具栏选项结果select文件 ( Ctrl + Shift + F )。
-
现在终于点击从上面的工具栏标记红色的执行button。
-
所有表的数据库大小现在存储在您的计算机上的文件中。
在@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