Wie können Sie feststellen, welche Tabellen in einer SQL Server 2005-Datenbank den meisten Speicherplatz beanspruchen?

90

Wie können Sie feststellen, welche Tabellen in einer SQL Server 2005-Datenbank den meisten Speicherplatz beanspruchen?

Ich bin sicher, dass es eine gespeicherte Systemprozedur gibt, die diese Informationen anzeigt.

Ich habe eine TEST-Datenbank, die von 1 TB auf 23 TB gewachsen ist. Wir führen derzeit viele Clientkonvertierungstests in der Datenbank durch, bei denen dieselbe gespeicherte Konvertierungsprozedur mehrmals ausgeführt wird. Es macht DELETEs, von denen ich sicher bin, dass sie das Transaktionsprotokoll erhöhen. Aber das brachte mich zum Nachdenken, diese Frage zu stellen.

die Info

Das große Problem ist die dbo.Download-Tabelle, sie erstellt massiven Speicher, der eigentlich nicht benötigt wird. Ich hatte 3 GB vor dem Abschneiden, dann 52 MB;)

Gerhard Weiss
quelle
2
Die Antworten von Marc_S und Barry waren einfach hervorragend, also habe ich beide positiv bewertet und darauf gewartet, welche die meisten positiven Stimmen erhalten hat, damit ich diese mit der "Akzeptierten Antwort" belohnen kann. Aber sie waren beide um 5 gebunden, also habe ich nur einen ausgewählt, aber ich habe beide verwendet. Vielen Dank Marc_S und Barry!
Gerhard Weiss

Antworten:

207

Probieren Sie dieses Skript aus - es listet die Anzahl der Zeilen und den von Datenzeilen verwendeten Speicherplatz (und den insgesamt verwendeten Speicherplatz) für alle Tabellen in Ihrer Datenbank auf:

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
quelle
6
+1 Genial. Beachten Sie, dass dies nicht die Größe der Datenindizes beinhaltet. Für mich hat es den Job erledigt.
Erick Robertson
39
Ich wusste das nicht, aber wenn Sie Management Studio verwenden, können Sie auch mit der rechten Maustaste auf die Datenbank klicken und zu Berichte -> Datenträgerverwendung nach Tabelle gehen, um dieselben Ergebnisse zu erhalten.
Rossisdead
@rossisdead, das ist eine witzige Information, die man wissen muss. Vielen Dank!
Nickmaovich
Ich bekomme 'Table' sys.tables 'existiert nicht'
Seano
@ Seano: Welche SQL Server-Version verwenden Sie? (Ausführen SELECT @@VERSION, um herauszufinden) Welche Datenbankkompatibilitätsstufe hat Ihre Datenbank?
marc_s
33

Verwenden Sie sp_spacedUsed

Exec sp_spaceused N'YourTableName'

Oder wenn Sie die sp_spaceusedfür jede Tabelle in Ihrer Datenbank ausführen möchten, können Sie diese SQL verwenden:

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

Das obige SQL ist von hier

Codierungsbadger
quelle
7
Für neuere Versionen von SQL Server können Sie auchexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK
1
@JNK sp_msforeachtableexistiert seit mindestens SQl Server 2000
SQLMenace
@ SQLMenace - danke für die Info. Ich habe vor dem Posten nicht nachgeforscht, wie alt es war, war mir aber nicht sicher, ob ich es finden würde, da es nicht dokumentiert ist.
JNK
4
Ein etwas einfacheres Beispiel: Sie können die EXECs überspringen und ausgefallene Zitate erstellen, indem Sie dies tun, sp_msforeachtable 'sp_spaceused [?]'wenn Sie möchten . Zurück zu SQL2000 verifiziert.
Mark
Mark Problem mit dieser Methode ist, dass es nicht als einzelne Ergebnismenge zurückgibt
Paul
7

Rossisdeads Kommentar beantwortete diese Frage am besten für mich. Ich wünschte, sie wäre nicht in einem Kommentar begraben. Dies ist nützlich für Leute wie mich, die nicht versuchen, die Lösung zu skripten (das OP hat nicht nach einem Code-Snippet gefragt).

Wenn Sie Management Studio verwenden, können Sie auch mit der rechten Maustaste auf die Datenbank klicken und unter Berichte -> Datenträgerverwendung nach Tabelle dieselben Ergebnisse erzielen

Hucker
quelle
Zur Verdeutlichung: Recht , die klicken Datenbank und nicht die Server - Instanz
dhollenbeck
4

Danke an @marc_s für die Antwort. Ich musste Daten im Vergleich zum Indexbereich kennen, also habe ich die Abfrage erweitert, um dies einzuschließen.

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
quelle