Como saber quais tabelas estão ocupando mais espaço em um banco de dados SQL Server 2005?

90

Como saber quais tabelas estão ocupando mais espaço em um banco de dados SQL Server 2005?

Tenho certeza de que há algum procedimento armazenado do sistema que mostra essas informações.

Eu tenho um banco de dados de teste que cresceu de 1 TB para 23 TB. No momento, estamos fazendo muitos testes de conversão de cliente no banco de dados, o que envolve a execução da mesma conversão Stored Procedure várias vezes. Ele faz DELETEs que tenho certeza que está aumentando o log de transações. Mas isso me fez pensar em fazer esta pergunta.

informação

o grande problema é a tabela dbo.Download, ela cria um armazenamento massivo que na verdade não é necessário, eu tinha 3 GB antes de truncá-lo, depois 52 MB;)

Gerhard Weiss
fonte
2
As respostas de Marc_S e Barry foram excelentes, então votei positivamente em ambos e estava esperando para ver qual teria mais votos positivos para que eu pudesse recompensar aquele com a "Resposta aceita". Mas os dois estavam empatados em 5, então escolhi apenas um, mas usei os dois. Muito obrigado Marc_S e Barry!
Gerhard Weiss

Respostas:

207

Experimente este script - ele listará o número de linhas e o espaço usado pelas linhas de dados (e o espaço total usado) para todas as tabelas em seu banco de dados:

SELECT 
 t.NAME AS TableName,
 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.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
WHERE 
 t.NAME NOT LIKE 'dt%' AND
 i.OBJECT_ID > 255 AND  
 i.index_id <= 1
GROUP BY 
 t.NAME, i.object_id, i.index_id, i.name 
ORDER BY 
 OBJECT_NAME(i.object_id) 
marc_s
fonte
6
+1 brilhante. Observe que isso não inclui o tamanho dos índices de dados. Para mim, porém, fez o trabalho.
Erick Robertson,
39
Eu não sabia disso, mas se você estiver usando o Management Studio, também pode clicar com o botão direito do mouse no banco de dados e ir para Relatórios -> Uso do disco por tabela para obter os mesmos resultados.
rossisdead
@rossisdead, essa é uma informação hilária de saber. Obrigado!
Nickmaovich
Eu obtenho 'Tabela' sys.tables 'does not exist'
Seano
@Seano: qual versão do SQL Server você está usando? (execute SELECT @@VERSIONpara descobrir) Qual nível de compatibilidade de banco de dados seu banco de dados tem ??
marc_s
33

Use sp_spacedUsed

Exec sp_spaceused N'YourTableName'

Ou se você deseja executar o sp_spaceusedpara cada tabela em seu banco de dados, você pode usar este SQL:

set nocount on
create table #spaceused (
  name nvarchar(120),
  rows char(11),
  reserved varchar(18),
  data varchar(18),
  index_size varchar(18),
  unused varchar(18)
)

declare Tables cursor for
  select name
  from sysobjects where type='U'
  order by name asc

OPEN Tables
DECLARE @table varchar(128)

FETCH NEXT FROM Tables INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN
  insert into #spaceused exec sp_spaceused @table
  FETCH NEXT FROM Tables INTO @table
END

CLOSE Tables
DEALLOCATE Tables 

select * from #spaceused
drop table #spaceused

exec sp_spaceused

O SQL acima é daqui

codingbadger
fonte
7
Para versões mais recentes do SQL Server, você também pode usarexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK
1
O @JNK sp_msforeachtableexiste desde pelo menos SQl Server 2000
SQLMenace
@SQLMenace - obrigado pela informação. Eu não pesquisei quantos anos ele tinha antes de postar, mas não tinha certeza se iria encontrá-lo, pois não é documentado.
JNK
4
Um exemplo um pouco mais simples: você pode escapar ignorando os EXECs e citações extravagantes, fazendo apenas sp_msforeachtable 'sp_spaceused [?]'se quiser. Verificado de volta para SQL2000.
Marque
O problema com esse método é que ele não retorna como um único conjunto de resultados
Paulo
7

O comentário de Rossisdead respondeu melhor a essa pergunta para mim, gostaria que não estivesse enterrado em um comentário. Isso será útil para pessoas como eu que não estão tentando fazer o script da solução (o OP não pediu um snippet de código)

Se você estiver usando o Management Studio, você também pode clicar com o botão direito do mouse no banco de dados e ir para Relatórios -> Uso do disco por tabela para os mesmos resultados

Hucker
fonte
Para enfatizar: clique com o botão direito no banco de dados e não na instância
dhollenbeck
4

Obrigado a @marc_s pela resposta. Eu precisava saber dados vs espaço de índice, então fui em frente e expandi a consulta para incluir isso.

SELECT TableName
    , SUM(DataRowCounts) AS DataRowCounts
    , SUM(DataTotalSpaceGB) AS DataTotalSpaceGB
    , SUM(DataSpaceUsedGB) AS DataSpaceUsedGB
    , SUM(DataUnusedSpaceGB) AS DataUnusedSpaceGB
    , SUM(IndexRowCounts) AS IndexRowCounts
    , SUM(IndexTotalSpaceGB) AS IndexTotalSpaceGB
    , SUM(IndexSpaceUsedGB) AS IndexSpaceUsedGB
    , SUM(IndexUnusedSpaceGB) AS IndexUnusedSpaceGB
    , SUM(DataTotalSpaceGB) + SUM(IndexTotalSpaceGB) AS TotalSpaceGB
FROM
(
SELECT t.NAME AS TableName
    , i.type_desc AS IndexType
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS DataTotalSpaceGB
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2))  ELSE 0 END AS DataSpaceUsedGB    
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS DataUnusedSpaceGB
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN SUM(p.Rows) ELSE 0 END AS DataRowCounts
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS IndexTotalSpaceGB
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2))  ELSE 0 END AS IndexSpaceUsedGB    
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS IndexUnusedSpaceGB  
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN SUM(p.Rows) ELSE 0 END AS IndexRowCounts
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 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
    AND s.Name = 'dbo' --update this filter
    AND t.Name = 'MyTable'
GROUP BY t.Name
    , i.type_desc
) x
GROUP BY TableName
ORDER BY TotalSpaceGB DESC
kjmerf
fonte