Po czym poznać, które tabele zajmują najwięcej miejsca w bazie danych SQL Server 2005?

90

Po czym poznać, które tabele zajmują najwięcej miejsca w bazie danych SQL Server 2005?

Jestem pewien, że istnieje procedura przechowywana w systemie, która pokazuje te informacje.

Mam bazę danych TEST, która rozrosła się z 1 TB do 23 TB. Obecnie wykonujemy wiele testów konwersji klienta w bazie danych, co wiąże się z wielokrotnym uruchamianiem tej samej procedury zapisanej w bazie konwersji. Robi DELETE, co na pewno zwiększa dziennik transakcji. Ale to sprawiło, że pomyślałem o zadaniu tego pytania.

info

dużym problemem jest tabela dbo.Download, tworzy ogromną przestrzeń dyskową, która w rzeczywistości nie jest potrzebna, miałem 3 GB przed jej obcięciem, a następnie 52 MB;)

Gerhard Weiss
źródło
2
Odpowiedzi Marc_S i Barry'ego były po prostu wybitne, więc zagłosowałem za nimi obu i czekałem, aby zobaczyć, który z nich uzyska najwięcej głosów, aby móc nagrodzić go „Zaakceptowaną odpowiedzią”. Ale obaj mieli remis na 5, więc wybrałem tylko jednego, ale użyłem obu. Dziękuję bardzo Marc_S i Barry!
Gerhard Weiss

Odpowiedzi:

208

Wypróbuj ten skrypt - wyświetli on liczbę wierszy i miejsce zajmowane przez wiersze danych (oraz całkowitą zajętą ​​przestrzeń) dla wszystkich tabel w Twojej bazie danych:

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
źródło
6
+1 genialny. Zwróć uwagę, że nie obejmuje to rozmiaru indeksów danych. Jednak dla mnie spełniło to zadanie.
Erick Robertson,
39
Nie wiedziałem o tym, ale jeśli używasz Management Studio, możesz również kliknąć bazę danych prawym przyciskiem myszy i przejść do Raporty -> Użycie dysku według tabeli, aby uzyskać te same wyniki.
Rossisdead
@rossisdead, to zabawna informacja. Dzięki!
Nickmaovich
Otrzymuję „Table” sys.tables „nie istnieje”
Seano
@Seano: jakiej wersji SQL Server używasz? (biegnij, SELECT @@VERSIONaby się dowiedzieć) Jaki poziom zgodności bazy danych ma twoja baza danych?
marc_s
33

Użyj sp_spacedUsed

Exec sp_spaceused N'YourTableName'

Lub jeśli chcesz wykonać sp_spaceuseddla każdej tabeli w swojej bazie danych, możesz użyć tego 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

Powyższy kod SQL pochodzi stąd

codingbadger
źródło
7
W przypadku nowszych wersji programu SQL Server można również użyćexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK
1
@JNK sp_msforeachtableistnieje od co najmniej SQl Server 2000
SQLMenace
@SQLMenace - dzięki za informację. Nie sprawdziłem, ile ma lat przed wysłaniem, ale nie byłem pewien, czy znajdę to, ponieważ jest nieudokumentowane.
JNK
4
Nieco prostszy przykład: można uciec z pominięciem Execs i fantazyjne cytowanie, wykonując tylko sp_msforeachtable 'sp_spaceused [?]'jeśli chcesz. Zweryfikowano z powrotem do SQL2000.
Mark
Zaznacz problem z tą metodą polega na tym, że nie zwraca ona jako pojedynczego zestawu wyników
Paul
7

Komentarz Rossisdeada najlepiej dla mnie odpowiedział na to pytanie, żałuję, że nie został ukryty w komentarzu. Będzie to przydatne dla osób takich jak ja, które nie próbują skryptu rozwiązania (OP nie poprosił o fragment kodu)

Jeśli używasz Management Studio, możesz również kliknąć bazę danych prawym przyciskiem myszy i przejść do opcji Raporty -> Użycie dysku według tabeli, aby uzyskać te same wyniki

Hucker
źródło
Dla podkreślenia: kliknij prawym przyciskiem myszy bazę danych, a nie instancję serwera
dhollenbeck
4

Dzięki @marc_s za odpowiedź. Musiałem znać dane i przestrzeń indeksów, więc poszedłem dalej i rozszerzyłem zapytanie, aby to uwzględnić.

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
źródło