Obter tamanho de todas as tabelas no database

Eu herdei um database bastante grande do SQL Server. Parece ocupar mais espaço do que eu esperava, dados os dados que ele contém.

Existe uma maneira fácil de determinar quanto espaço no disco cada tabela está consumindo?

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 

Se você estiver usando o SQL Server Management Studio (SSMS), em vez de executar uma consulta ( que, no meu caso, retornou linhas duplicadas ), poderá executar um relatório padrão .

  1. Clique com o botão direito no database
  2. Navegue para Relatórios> Relatórios Padrão> Uso de Disco por Tabela

Nota: O nível de compatibilidade do database deve ser definido como 90 ou acima para que isso funcione corretamente. Consulte http://msdn.microsoft.com/pt-br/library/bb510680.aspx

sp_spaceused pode obter informações sobre o espaço em disco usado por uma tabela, exibição indexada ou o database inteiro.

Por exemplo:

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

Isso informa as informações de uso do disco para a tabela ContactInfo.

Para usar isso para todas as tabelas de uma só vez:

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

Você também pode obter o uso do disco a partir da funcionalidade de relatórios padrão do SQL Server com o botão direito do mouse. Para chegar a esse relatório, navegue a partir do object do servidor no Pesquisador de Objetos, vá para o object Bancos de Dados e clique com o botão direito do mouse em qualquer database. No menu que aparece, selecione Relatórios, depois Relatórios padrão e, em seguida, “Uso do disco por partição: [DatabaseName]”.

  exec sp_spaceused N'dbo.MyTable' 

Para todas as tabelas, use .. (adicionando dos comentários de Paul)

 exec sp_MSForEachTable 'exec sp_spaceused [?]' 

Depois de algumas pesquisas, não consegui encontrar uma maneira fácil de obter informações sobre todas as tabelas. Existe um prático procedimento armazenado chamado sp_spaceused que retornará todo o espaço usado pelo database. Se fornecido com um nome de tabela, ele retorna o espaço usado por essa tabela. No entanto, os resultados retornados pelo procedimento armazenado não são classificáveis, pois as colunas são valores de caractere.

O script a seguir gerará as informações que estou procurando.

 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 

Aqui está outro método: usando o SQL Server Management Studio , no Object Explorer , vá para o database e selecione Tabelas

insira a descrição da imagem aqui

Em seguida, abra os Detalhes do Pesquisador de Objetos (pressionando F7 ou indo para Visualizar-> Detalhes do Pesquisador de Objetos ). Na página de detalhes do explorador de objects, clique com o botão direito do mouse no header da coluna e ative as colunas que você gostaria de ver na página. Você pode classificar os dados por qualquer coluna também.

insira a descrição da imagem aqui

As consultas acima são boas para encontrar a quantidade de espaço usada pela tabela (índices incluídos), mas se você quiser comparar quanto espaço é usado pelos índices na tabela, use esta consulta:

 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 

Se você precisa calcular exatamente os mesmos números, que estão na página ‘propriedades da tabela – armazenamento’ no SSMS, você precisa contá-los com o mesmo método que foi feito no SSMS (funciona para o SQL Server 2005 e acima … e também funciona corretamente para tabelas com campos LOB – porque apenas contar “used_pages” não é suficiente para mostrar o tamanho exato do índice):

 ;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 

Uma pequena mudança na resposta de Mar_c, já que voltei a esta página com tanta frequência, ordenada pela maioria das primeiras linhas:

 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 

Isso fornecerá os tamanhos e as contagens de registros para cada tabela.

 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 

Usamos o particionamento de tabelas e tivemos alguns problemas com as consultas fornecidas acima devido a registros duplicados.

Para aqueles que precisam disso, você pode encontrar abaixo a consulta executada pelo SQL Server 2014 ao gerar o relatório “Uso de disco por tabela”. Eu suponho que também funciona com versões anteriores do SQL Server.

Ele funciona como um encanto.

 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 

Para obter todos os tamanhos de tabela em um database, você pode usar esta consulta:

 Exec sys.sp_MSforeachtable ' sp_spaceused "?" ' 

E você pode alterá-lo para inserir todo o resultado em uma tabela temporária e depois selecionar a tabela temporária.

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

Eu adicionei mais algumas colunas em cima da resposta do 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 

Aqui está uma maneira de obter os tamanhos de todas as tabelas rapidamente com as seguintes etapas:

  1. Escreva os comandos T-SQL fornecidos para listar todas as tabelas do database:

     select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE' 
  2. Agora, copie a lista de tabelas de database e copie-a em uma nova janela do analisador de consultas

     exec sp_spaceused table1 exec sp_spaceused table2 exec sp_spaceused table3 exec sp_spaceused table4 exec sp_spaceused table5 
  3. No analisador de consultas SQL, selecione na opção da barra de ferramentas superior Resultados para arquivo ( Ctrl + Shift + F ).

  4. Agora finalmente aperte o botão Execute vermelho marcado na barra de ferramentas acima.

  5. O tamanho do banco de dados de todas as tabelas agora é armazenado em um arquivo no seu computador.

    Digite a descrição da imagem aqui

Extensão para @xav resposta que manipulava partições de tabela para obter tamanho em MB e GB. Testado no SQL Server 2008/2012 (Comentou uma linha onde 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 

Minha postagem é relevante apenas para o SQL Server 2000 e foi testada para funcionar em meu ambiente.

Este código acessa Todos os possíveis bancos de dados de uma única instância , não apenas um único database.

Eu uso duas tabelas temporárias para ajudar a coletar os dados apropriados e, em seguida, despejo os resultados em uma tabela ‘Live’.

Os dados retornados são: DatabaseName, DatabaseTableName, Rows (na Tabela), dados (tamanho da tabela em KB que parece), dados de input (acho isso útil para saber quando executei pela última vez o script).

A queda para este código é que o campo ‘data’ não é armazenado como int (os caracteres ‘KB’ são mantidos nesse campo), e isso seria útil (mas não totalmente necessário) para ordenação.

Espero que este código ajude alguém e economize tempo!

 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] 

Caso você precise saber, a tabela rsp_DatabaseTableSizes foi criada por meio de:

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

Em um prompt de comando usando o OSQL :

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

Como uma simples extensão da resposta de marc_s (a que foi aceita), isso é ajustado para retornar a contagem de colunas e permitir a filtragem:

 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 

Riffing na resposta do @Mark acima, adicionou o @ updateusage = ‘true’ para forçar as statistics de tamanho mais recentes ( 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