¿Cómo puede saber qué tablas ocupan más espacio en una base de datos de SQL Server 2005?

90

¿Cómo puede saber qué tablas ocupan más espacio en una base de datos de SQL Server 2005?

Estoy seguro de que hay algún procedimiento almacenado en el sistema que muestra esta información.

Tengo una base de datos TEST que creció de 1 tb a 23 tb. Actualmente estamos haciendo muchas pruebas de conversión de clientes en la base de datos, lo que implica ejecutar el mismo procedimiento almacenado de conversión varias veces. Elimina, lo que estoy seguro de que aumenta el registro de transacciones. Pero esto me hizo pensar en hacer esta pregunta.

info

el gran problema es la tabla dbo.Download, crea un almacenamiento masivo que en realidad no es necesario, tenía 3GB antes de truncarlo, luego 52MB;)

Gerhard Weiss
fuente
2
Las respuestas de Marc_S y Barry fueron sobresalientes, así que voté a ambos y estaba esperando a ver cuál obtuvo más votos para poder recompensarlo con la "Respuesta Aceptada". Pero ambos estaban empatados a 5, así que elegí uno, pero usé ambos. ¡Muchas gracias Marc_S y Barry!
Gerhard Weiss

Respuestas:

208

Pruebe este script: enumerará el número de filas y el espacio utilizado por las filas de datos (y el espacio total utilizado) para todas las tablas en su base de datos:

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
fuente
6
+1 Brillante. Tenga en cuenta que esto no incluye el tamaño de los índices de datos. Para mí, sin embargo, hizo el trabajo.
Erick Robertson
39
No lo sabía, pero si está utilizando Management Studio, también puede hacer clic derecho en la base de datos e ir a Informes -> Uso de disco por tabla para obtener los mismos resultados.
rossisdead
@rossisdead, esa es una información muy divertida para saber. ¡Gracias!
Nickmaovich
Recibo 'Table' sys.tables 'doesn't exist'
Seano
@Seano: ¿Qué versión de SQL Server estás usando? (ejecutar SELECT @@VERSIONpara averiguarlo) ¿Qué nivel de compatibilidad de base de datos tiene su base de datos?
marc_s
33

Utilice sp_spacedUsed

Exec sp_spaceused N'YourTableName'

O si desea ejecutar el sp_spaceusedpara cada tabla en su base de datos, puede 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

El SQL anterior es de aquí

codificador
fuente
7
Para las versiones más recientes de SQL Server, también puede usarexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK
1
@JNK sp_msforeachtableexiste desde al menos SQl Server 2000
SQLMenace
@SQLMenace - gracias por la información. No investigué cuántos años tenía antes de publicarlo, pero no estaba seguro de encontrarlo ya que no está documentado.
JNK
4
Un ejemplo un poco más simple: puede saltarse los EXEC y las citas sofisticadas sp_msforeachtable 'sp_spaceused [?]'si lo desea. Verificado de nuevo a SQL2000.
Mark
Marque el problema con este método es que no regresa como un conjunto de resultados único
Paul
7

El comentario de Rossisdead respondió a esta pregunta lo mejor para mí, desearía que no estuviera enterrado en un comentario. Esto será útil para personas como yo que no intentan escribir la solución (el OP no solicitó un fragmento de código)

Si está utilizando Management Studio, también puede hacer clic derecho en la base de datos e ir a Informes -> Uso de disco por tabla para obtener los mismos resultados.

Hucker
fuente
Para enfatizar: haga clic con el botón derecho en la base de datos y no en la instancia
dhollenbeck
4

Gracias a @marc_s por la respuesta. Necesitaba saber los datos frente al espacio de índice, así que seguí adelante y amplié la consulta para incluir eso.

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
fuente