Comment savoir quelles tables occupent le plus d'espace dans une base de données SQL Server 2005?

90

Comment savoir quelles tables occupent le plus d'espace dans une base de données SQL Server 2005?

Je suis sûr qu'il existe une procédure stockée par le système qui affiche ces informations.

J'ai une base de données TEST qui est passée de 1 To à 23 To. Nous effectuons actuellement de nombreux tests de conversion client dans la base de données, ce qui implique d'exécuter plusieurs fois la même procédure stockée de conversion. Il supprime ce qui, j'en suis sûr, augmente le journal des transactions. Mais cela m'a fait réfléchir à poser cette question.

Info

le gros problème est la table dbo.Download, elle crée un stockage massif qui n'est en fait pas nécessaire, j'avais 3 Go avant de le tronquer, puis 52 Mo;)

Gerhard Weiss
la source
2
Les réponses de Marc_S et Barry étaient tout simplement exceptionnelles, alors j'ai voté pour les deux et j'attendais de voir laquelle avait obtenu le plus de votes pour que je puisse récompenser celle-là avec la «réponse acceptée». Mais ils étaient tous les deux à égalité à 5, alors j'en ai choisi un mais j'ai utilisé les deux. Merci beaucoup Marc_S et Barry!
Gerhard Weiss

Réponses:

207

Essayez ce script - il listera le nombre de lignes et l'espace utilisé par les lignes de données (et l'espace total utilisé) pour toutes les tables de votre base de données:

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
la source
6
+1 Brillant. Notez que cela n'inclut pas la taille des index de données. Pour moi, cependant, cela a fait le travail.
Erick Robertson le
39
Je ne le savais pas, mais si vous utilisez Management Studio, vous pouvez également faire un clic droit sur la base de données et aller dans Rapports -> Utilisation du disque par table pour les mêmes résultats.
rossisdead
@rossisdead, c'est une information hilarante à connaître. Merci!
Nickmaovich
Je reçois 'Table' sys.tables 'n'existe pas'
Seano
@Seano: quelle version de SQL Server utilisez-vous? (courir SELECT @@VERSIONpour savoir) Quel est le niveau de compatibilité de votre base de données?
marc_s
33

Utiliser sp_spacedUsed

Exec sp_spaceused N'YourTableName'

Ou si vous souhaitez exécuter le sp_spaceusedpour chaque table de votre base de données, vous pouvez utiliser ce 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

Le SQL ci-dessus est d' ici

codingbadger
la source
7
Pour les versions plus récentes de SQL Server, vous pouvez également utiliserexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK
1
@JNK sp_msforeachtableexiste depuis au moins SQl Server 2000
SQLMenace
@SQLMenace - merci pour l'info. Je n'ai pas recherché son âge avant de le publier, mais je n'étais pas sûr de le trouver car il n'est pas documenté.
JNK
4
Un exemple un peu plus simple: vous pouvez vous en sortir en sautant les EXEC et en citant de fantaisie, en faisant juste sp_msforeachtable 'sp_spaceused [?]'si vous le souhaitez. Vérifié à nouveau à SQL2000.
Mark
Marquer le problème avec cette méthode est qu'elle ne revient pas sous la forme d'un ensemble de résultats unique
Paul
7

Le commentaire de Rossisdead a répondu à cette question le mieux pour moi, j'aimerais qu'il ne soit pas enterré dans un commentaire. Cela sera utile pour les personnes comme moi qui n'essaient pas de créer un script de la solution (l'OP n'a pas demandé d'extrait de code)

Si vous utilisez Management Studio, vous pouvez également faire un clic droit sur la base de données et aller dans Rapports -> Utilisation du disque par table pour les mêmes résultats

Hucker
la source
Pour mettre l'accent: faites un clic droit sur
faites un
4

Merci à @marc_s pour la réponse. J'avais besoin de connaître les données par rapport à l'espace d'index, alors je suis allé de l'avant et j'ai développé la requête pour l'inclure.

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
la source