Uzyskaj rozmiar wszystkich tabel w bazie danych


1271

Odziedziczyłem dość dużą bazę danych SQL Server. Wydaje się, że zajmuje więcej miejsca, niż się spodziewałbym, biorąc pod uwagę zawarte w nim dane.

Czy istnieje prosty sposób, aby określić, ile miejsca na dysku zajmuje każdy stół?


do jakich ról masz dostęp? Czy jesteś DBA, czy jest to zarządzane za pośrednictwem hosta, klienta lub podobnego?
Rob Allen,

możliwy duplikat wielkości tabeli i indeksu w SQL Server
Joe Stefanelli

@RobAllen Mam pełny dostęp do bazy danych, więc wystarczy skrypt wymagający dowolnej roli.
Eric,


Odpowiedzi:


2593
SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows,
    SUM(a.total_pages) * 8 AS TotalSpaceKB, 
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB, 
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB, 
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB
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 OUTER 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 
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    TotalSpaceMB DESC, t.Name

7
Głupie pytanie, ale czy jest możliwe, że to zapytanie może powodować blokowanie wierszy?
GEMI,

7
Indeksy również zajmują miejsce, a ilość miejsca wykorzystywanego przez indeksy można znaleźć za pomocą tego zapytania poniżej.
Jens Frandsen

6
Twój skrypt ma problemy z filtrowanymi indeksami: Dla każdego filtrowanego indeksu dla danej tabeli widzę dodatkowy wiersz z nazwą tej tabeli w wynikach. „RowCounts” każdego z tych dodatkowych wierszy odpowiada liczbie wierszy objętych jednym z filtrowanych indeksów. (na Sql2012)
Akos Lukacs,

37
@Todd: niektórzy ludzie chcą, aby tak było - inni chcą według nazwy tabeli - wybierz, dostosuj kod w razie potrzeby ....
marc_s

12
Jeśli tabele są podzielone na partycje, wyświetlają się wiele razy bez żadnego wskazania, co się dzieje. Możesz dodać numer p.partition_n do listy wyboru lub możesz SUM (p.Rows) i usunąć go z grupy przez.
PRMan

561

Jeśli używasz programu SQL Server Management Studio (SSMS), zamiast uruchamiać zapytanie ( które w moim przypadku zwróciło zduplikowane wiersze ), możesz uruchomić standardowy raport

  1. Kliknij bazę danych prawym przyciskiem myszy
  2. Przejdź do Raporty> Raporty standardowe> Wykorzystanie dysku według tabeli

Uwaga: Poziom zgodności bazy danych musi być ustawiony na 90 lub więcej, aby działał poprawnie. Zobacz http://msdn.microsoft.com/en-gb/library/bb510680.aspx


54
W Management Studio 2012 możesz: Przeglądać szczegóły Eksploratora obiektów (F7) i nawigować do „Tabeli” w Eksploratorze obiektów. W Szczegółach kliknij prawym przyciskiem myszy nagłówek i wybierz rozmiar kolumn.
ValGe

3
za doradzanie nowej funkcjonalności w SSMS 2012. Dla nas, staroświeckich, nigdy nie mieliśmy tego dostępnego. Więc zrobiliśmy to po prostu starą metodą TSQL :)
GoldBishop

3
Wierzcie lub nie, czasem zwykli śmiertelnicy (programiści) chcieliby zobaczyć te informacje i nie mamy uprawnień do korzystania z wbudowanego raportu, ale możemy uruchomić TSQL w zaakceptowanej odpowiedzi. :) FYI (BTW, wciąż głosowałem na twoją odpowiedź)
Andrew Steitz

8
Nie wydaje się być obecny w Azure SQL :-(
Simon_Weaver

1
Wiem, że to nie jest poważne, ale, proszę, po prostu odsuwasz zmarginalizowane grupy od inżynierii i techniki, z tym tokiem rozumowania powtarzanym wszędzie. Powinieneś nauczyć się obu, ale nie powinieneś karać ludzi za używanie narzędzi oszczędzających czas, aby pracować mądrzej i szybciej. (Chociaż czasem SSMS wydaje się być „narzędziem spowalniającym” ...: X) Osobiście odczyty danych tabelarycznych są zwykle bardziej wyraźne w GUI, chociaż narzędzia zbudowane przez Microsoft są zwykle wyjątkiem od wszystkiego, co dotyczy interfejsu użytkownika.
Julia McGuigan

102

sp_spaceused może uzyskać informacje na temat miejsca na dysku używanego przez tabelę, widok indeksowany lub całą bazę danych.

Na przykład:

USE MyDatabase; GO

EXEC sp_spaceused N'User.ContactInfo'; GO

Podaje informacje o użyciu dysku dla tabeli ContactInfo.

Aby użyć tego dla wszystkich tabel jednocześnie:

USE MyDatabase; GO

sp_msforeachtable 'EXEC sp_spaceused [?]' GO

Użycie dysku można również uzyskać z poziomu funkcji Standardowe raporty programu SQL Server, klikając prawym przyciskiem myszy. Aby przejść do tego raportu, przejdź od obiektu serwera w Eksploratorze obiektów, przejdź do obiektu Bazy danych, a następnie kliknij prawym przyciskiem myszy dowolną bazę danych. Z wyświetlonego menu wybierz Raporty, następnie Raporty standardowe, a następnie „Wykorzystanie dysku według partycji: [nazwa bazy danych]”.


3
Jest to fajne, chociaż użycie sp_msforeachtableSSMS może łatwo wywołać a, System.OutOfMemoryExceptionjeśli masz dużą liczbę tabel, więc lepszym pomysłem może być użycie tabeli tymczasowej do przechowywania wyników.
syneticon-dj

1
Główny problem, jaki widzę w sp_spacedused, polega na tym, że wydaje się, że zwraca dane w formacie czytelnym dla człowieka (np. W kolumnie „zarezerwowany” w moim przypadku miał „152 KB”). Zakładam, że odpowiednio zmieni się na MB / GB. Jest to wyraźnie przydatne w wielu sytuacjach, ale nie wtedy, gdy trzeba zastosować logikę opartą na rozmiarze lub porównać wartości lub cokolwiek innego. Szukałem sposobu, aby to wyłączyć, ale nie znalazłem żadnego (używam SQL Server 2005 :()
DarthPablo,

55

Oto kolejna metoda: używając SQL Server Management Studio , w Eksploratorze obiektów , przejdź do bazy danych i wybierz Tabele

wprowadź opis zdjęcia tutaj

Następnie otwórz Szczegóły Eksploratora obiektów (naciskając klawisz F7 lub przechodząc do Widok-> Szczegóły Eksploratora obiektów ). Na stronie szczegółów eksploratora obiektów kliknij prawym przyciskiem myszy nagłówek kolumny i włącz kolumny, które chcesz zobaczyć na stronie. Możesz sortować dane według dowolnej kolumny.

wprowadź opis zdjęcia tutaj


Tak, SSMS na platformie Azure nie ma niektórych funkcji w porównaniu z wersją lokalną.
Sparrow

@batmaci Nie jestem pewien, czy to w ogóle działało, kiedy skomentowałeś bazy danych Azure SQL, ale wydaje się, że przynajmniej częściowo działa teraz w najnowszych wersjach SSMS. Wydaje mi się, że limit czasu dla metadanych tabeli upłynął, ale wydaje się, że zwraca kilka (3-10) tabel, w tym (niezawodnie) wybraną tabelę. Wybierz tabelę i kliknij Odśwież, aby zobaczyć tabelę, którą chcesz, jeśli nie jest wyświetlana.
pcdev

Azure nie jest „prawdziwym” serwerem SQL (ha ha)
Reversed Engineer

Użyłem tego na
platformie

Możesz także wyeksportować listę do pliku CSV za pomocą narzędzia takiego jak NirSoft SysExporter: nirsoft.net/utils/sysexp.html
maks

39

Po kilku poszukiwaniach nie mogłem znaleźć łatwego sposobu na uzyskanie informacji o wszystkich tabelach. Istnieje przydatna procedura składowana o nazwie sp_spaceused, która zwróci całą przestrzeń używaną przez bazę danych. Jeśli podano nazwę tabeli, zwraca miejsce używane przez tę tabelę. Jednak wyniki zwrócone przez procedurę przechowywaną nie są sortowalne, ponieważ kolumny są wartościami znakowymi.

Poniższy skrypt wygeneruje informacje, których szukam.

create table #TableSize (
    Name varchar(255),
    [rows] int,
    reserved varchar(255),
    data varchar(255),
    index_size varchar(255),
    unused varchar(255))
create table #ConvertedSizes (
    Name varchar(255),
    [rows] int,
    reservedKb int,
    dataKb int,
    reservedIndexSize int,
    reservedUnused int)

EXEC sp_MSforeachtable @command1="insert into #TableSize
EXEC sp_spaceused '?'"
insert into #ConvertedSizes (Name, [rows], reservedKb, dataKb, reservedIndexSize, reservedUnused)
select name, [rows], 
SUBSTRING(reserved, 0, LEN(reserved)-2), 
SUBSTRING(data, 0, LEN(data)-2), 
SUBSTRING(index_size, 0, LEN(index_size)-2), 
SUBSTRING(unused, 0, LEN(unused)-2)
from #TableSize

select * from #ConvertedSizes
order by reservedKb desc

drop table #TableSize
drop table #ConvertedSizes

Po zobaczeniu powyższego za pomocą foreach i SP zamierzał napisać coś takiego, cieszę się, że przewinąłem w dół, aby zobaczyć, że zaoszczędziło mi to trochę czasu.
Brad

37
 exec  sp_spaceused N'dbo.MyTable'

Do wszystkich tabel użyj .. (dodając z komentarzy Pawła)

exec sp_MSForEachTable 'exec sp_spaceused [?]'

5
Podstępne - zmieniłeś, z exec sp_helpdbktórego nie widać nic o tabelach, na exec sp_spaceusedco - ale tylko dla jednej tabeli na raz ... nie daje ci przeglądu, jakie masz tabele i ile mają wierszy i jak zajmują dużo miejsca.
marc_s

4
exec sp_MSForEachTable 'exec sp_spaceused [?]'
Paul

27

Powyższe zapytania są przydatne do znalezienia miejsca zajmowanego przez tabelę (włącznie z indeksami), ale jeśli chcesz porównać, ile miejsca zajmują indeksy w tabeli, skorzystaj z tego zapytania:

SELECT
    OBJECT_NAME(i.OBJECT_ID) AS TableName,
    i.name AS IndexName,
    i.index_id AS IndexID,
    8 * SUM(a.used_pages) AS 'Indexsize(KB)'
FROM
    sys.indexes AS i
    JOIN sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id
    JOIN sys.allocation_units AS a ON a.container_id = p.partition_id
WHERE
    i.is_primary_key = 0 -- fix for size discrepancy
GROUP BY
    i.OBJECT_ID,
    i.index_id,
    i.name
ORDER BY
    OBJECT_NAME(i.OBJECT_ID),
    i.index_id

Z jakiego powodu sumowanie kolumny Indexsize (KB) dla konkretnej tabeli nie zgadza się z wartością index_size z sp_spaceused?
Derek

@Derek Naprawił swoją odpowiedź, dodając where [i].[is_primary_key] = 0. Teraz rozmiary powinny się zgadzać.
CodeAngry 10.01.2019

Dziękuję, ale to też nie działa. Mam (bardzo małą) testową bazę danych, tabela zainteresowań ma dwa indeksy - główny indeks klastrowy w jednej kolumnie i indeks nieklastrowany w dwóch pozostałych kolumnach. To zapytanie mówi, że każdy z nich używa 16kB, ale sp_spaceused mówi, że całkowite użycie indeksu wynosi 24kB. Częścią mojego zamieszania jest to, że porównując to zapytanie z „UsedSpaceKB” przyjętej odpowiedzi, nie widzę żadnej różnicy. Te same sprzężenia, po prostu brakuje dodania sys.tables. Czy coś pomijam, czy to zapytanie jest z natury zepsute?
Derek

Mam duże bazy danych. I rozmiary pasują do sp_spaceused. Mierzę GB, więc kilka megapasów niepasujących to niewiele. Nie dbam o dokładne rozmiary, to tylko pomysł.
CodeAngry

14

Jeśli chcesz obliczyć dokładnie te same liczby, które znajdują się na stronie „właściwości tabeli - przechowywanie” w SSMS, musisz policzyć je tą samą metodą, co w SSMS (działa dla serwera SQL 2005 i nowszych ... a także działa poprawnie dla tabel z polami LOB - ponieważ samo zliczenie „used_pages” nie wystarczy, aby pokazać dokładny rozmiar indeksu):

;with cte as (
SELECT
t.name as TableName,
SUM (s.used_page_count) as used_pages_count,
SUM (CASE
            WHEN (i.index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)
            ELSE lob_used_page_count + row_overflow_used_page_count
        END) as pages
FROM sys.dm_db_partition_stats  AS s 
JOIN sys.tables AS t ON s.object_id = t.object_id
JOIN sys.indexes AS i ON i.[object_id] = t.[object_id] AND s.index_id = i.index_id
GROUP BY t.name
)
select
    cte.TableName, 
    cast((cte.pages * 8.)/1024 as decimal(10,3)) as TableSizeInMB, 
    cast(((CASE WHEN cte.used_pages_count > cte.pages 
                THEN cte.used_pages_count - cte.pages
                ELSE 0 
          END) * 8./1024) as decimal(10,3)) as IndexSizeInMB
from cte
order by 2 desc

14

Rozszerzenie @xav odpowiada na obsługiwane partycje tabel, aby uzyskać rozmiar w MB i GB. Testowane na SQL Server 2008/2012 (skomentowano wiersz gdzie is_memory_optimized = 1)

SELECT
    a2.name AS TableName,
    a1.rows as [RowCount],
    --(a1.reserved + ISNULL(a4.reserved,0)) * 8 AS ReservedSize_KB,
    --a1.data * 8 AS DataSize_KB,
    --(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS IndexSize_KB,
    --(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS UnusedSize_KB,
    CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_MB,
    CAST(ROUND(a1.data * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_MB,
    CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_MB,
    CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_MB,
    --'| |' Separator_MB_GB,
    CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_GB,
    CAST(ROUND(a1.data * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_GB,
    CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_GB,
    CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_GB
FROM
    (SELECT 
        ps.object_id,
        SUM (CASE WHEN (ps.index_id < 2) THEN row_count ELSE 0 END) AS [rows],
        SUM (ps.reserved_page_count) AS reserved,
        SUM (CASE
                WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
            END
            ) AS data,
        SUM (ps.used_page_count) AS used
    FROM sys.dm_db_partition_stats ps
        --===Remove the following comment for SQL Server 2014+
        --WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
    GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN 
    (SELECT 
        it.parent_id,
        SUM(ps.reserved_page_count) AS reserved,
        SUM(ps.used_page_count) AS used
     FROM sys.dm_db_partition_stats ps
     INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
     WHERE it.internal_type IN (202,204)
     GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id ) 
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
--AND a2.name = 'MyTable'       --Filter for specific table
--ORDER BY a3.name, a2.name
ORDER BY ReservedSize_MB DESC

także lepszy porządek sortowania.
Pxtl,

To powinna być najlepsza odpowiedź.
Baodad

14

Na platformie Azure użyłem tego:

Powinieneś mieć SSMS v17.x

Użyłem;

wprowadź opis zdjęcia tutaj

Z tym, jak wspomniał User Sparrow :

Otwórz Databases> i wybierz Tabele , a
następnie naciśnij klawisz F7 Powinieneś zobaczyć row count
: wprowadź opis zdjęcia tutaj

SSMS tutaj jest podłączony do baz danych Azure


3
F7 jest mocno niewykorzystany.
cskwg

1
Nie miałem pojęcia, że ​​to istnieje, wstydzę się siebie: p Dzięki!
lollancf37

Ma problem z tabelami zoptymalizowanymi pod kątem pamięci (właśnie przetestowałem po zobaczeniu tego postu :)
Amirreza,

11

Używamy partycjonowania tabel i mieliśmy problemy z powyższymi zapytaniami z powodu duplikatów rekordów.

Dla tych, którzy tego potrzebują, możesz znaleźć poniżej zapytania uruchomionego przez SQL Server 2014 podczas generowania raportu „Wykorzystanie dysku według tabeli”. Zakładam, że działa również z poprzednimi wersjami SQL Server.

To działa jak urok.

SELECT
    a2.name AS [tablename],
    a1.rows as row_count,
    (a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved, 
    a1.data * 8 AS data,
    (CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,
    (CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused
FROM
    (SELECT 
        ps.object_id,
        SUM (
            CASE
                WHEN (ps.index_id < 2) THEN row_count
                ELSE 0
            END
            ) AS [rows],
        SUM (ps.reserved_page_count) AS reserved,
        SUM (
            CASE
                WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
            END
            ) AS data,
        SUM (ps.used_page_count) AS used
    FROM sys.dm_db_partition_stats ps
        WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
    GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN 
    (SELECT 
        it.parent_id,
        SUM(ps.reserved_page_count) AS reserved,
        SUM(ps.used_page_count) AS used
     FROM sys.dm_db_partition_stats ps
     INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
     WHERE it.internal_type IN (202,204)
     GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id ) 
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
ORDER BY a3.name, a2.name

Dzięki za skrypt, który pasuje do tego, jak robi to SSMS i poprawnie obsługuje partycje.
Mike

8
-- Show the size of all the tables in a database sort by data size descending
SET NOCOUNT ON
DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
DECLARE @cmd1 varchar(500)
SET @cmd1 = 'exec sp_spaceused ''?'''

INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
EXEC sp_msforeachtable @command1=@cmd1

SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC

8

Mała zmiana w odpowiedzi Mar_c , ponieważ tak często wracam na tę stronę, uporządkowaną według pierwszego wiersza:

SELECT
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    SUM(a.total_pages) * 8 AS TotalSpaceKB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB,
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
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 OUTER 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
GROUP BY
    t.Name, s.Name, p.Rows
ORDER BY
    --p.rows DESC --Uncomment to order by amount rows instead of size in KB.
    SUM(a.total_pages) DESC 

5

To da ci rozmiary i liczbę rekordów dla każdego stołu.

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
-- Get a list of tables and their sizes on disk
ALTER PROCEDURE [dbo].[sp_Table_Sizes]
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
DECLARE @table_name VARCHAR(500)  
DECLARE @schema_name VARCHAR(500)  
DECLARE @tab1 TABLE( 
        tablename VARCHAR (500) collate database_default 
       ,schemaname VARCHAR(500) collate database_default 
) 

CREATE TABLE #temp_Table ( 
        tablename sysname 
       ,row_count INT 
       ,reserved VARCHAR(50) collate database_default 
       ,data VARCHAR(50) collate database_default 
       ,index_size VARCHAR(50) collate database_default 
       ,unused VARCHAR(50) collate database_default  
) 

INSERT INTO @tab1  
SELECT Table_Name, Table_Schema  
FROM information_schema.tables  
WHERE TABLE_TYPE = 'BASE TABLE' 

DECLARE c1 CURSOR FOR 
SELECT Table_Schema + '.' + Table_Name   
FROM information_schema.tables t1  
WHERE TABLE_TYPE = 'BASE TABLE' 

OPEN c1 
FETCH NEXT FROM c1 INTO @table_name 
WHILE @@FETCH_STATUS = 0  
BEGIN   
        SET @table_name = REPLACE(@table_name, '[','');  
        SET @table_name = REPLACE(@table_name, ']','');  

        -- make sure the object exists before calling sp_spacedused 
        IF EXISTS(SELECT id FROM sysobjects WHERE id = OBJECT_ID(@table_name)) 
        BEGIN 
               INSERT INTO #temp_Table EXEC sp_spaceused @table_name, false; 
        END 

        FETCH NEXT FROM c1 INTO @table_name 
END 
CLOSE c1 
DEALLOCATE c1 

SELECT  t1.* 
       ,t2.schemaname  
FROM #temp_Table t1  
INNER JOIN @tab1 t2 ON (t1.tablename = t2.tablename ) 
ORDER BY schemaname,t1.tablename; 

DROP TABLE #temp_Table
END

2
Jeśli publikujesz kod, XML lub próbki danych, PROSZĘ podświetl te wiersze w edytorze tekstu i kliknij przycisk „próbki kodu” ( { }) na pasku narzędzi edytora, aby ładnie sformatować i podświetlić składnię!
marc_s

4

Aby uzyskać cały rozmiar tabeli w jednej bazie danych, możesz użyć tego zapytania:

Exec sys.sp_MSforeachtable ' sp_spaceused "?" '

Możesz to zmienić, aby wstawić wszystkie wyniki do tabeli temp, a następnie wybrać z tabeli temp.

Insert into #TempTable Exec sys.sp_MSforeachtable ' sp_spaceused "?" ' 
Select * from #TempTable


3

Oto sposób szybkiego uzyskania rozmiarów wszystkich tabel, wykonując następujące czynności:

  1. Napisz podane komendy T-SQL, aby wyświetlić wszystkie tabele bazy danych:

    select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
  2. Teraz skopiuj listę tabel bazy danych i skopiuj ją do nowego okna analizatora zapytań

    exec sp_spaceused table1
    exec sp_spaceused table2
    exec sp_spaceused table3
    exec sp_spaceused table4
    exec sp_spaceused table5
  3. W analizatorze zapytań SQL wybierz z górnego paska narzędzi opcję Wyniki do pliku ( Ctrl+ Shift+ F).

  4. Teraz w końcu naciśnij czerwony przycisk Wykonaj zaznaczony na powyższym pasku narzędzi .

  5. Rozmiar bazy danych wszystkich tabel jest teraz przechowywany w pliku na komputerze.

    Wpisz opis zdjęcia tutaj


2

Dodałem jeszcze kilka kolumn na górze odpowiedzi marc_s:

with fs
as
(
select i.object_id,
        p.rows AS RowCounts,
        SUM(a.total_pages) * 8 AS TotalSpaceKb
from     sys.indexes i 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 
    i.OBJECT_ID > 255 
GROUP BY 
    i.object_id,
    p.rows
)

SELECT 
    t.NAME AS TableName,
    fs.RowCounts,
    fs.TotalSpaceKb,
    t.create_date,
    t.modify_date,
    ( select COUNT(1)
        from sys.columns c 
        where c.object_id = t.object_id ) TotalColumns    
FROM 
    sys.tables t INNER JOIN      
    fs  ON t.OBJECT_ID = fs.object_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
ORDER BY 
    t.Name

1

Mój post dotyczy tylko SQL Server 2000 i został przetestowany do pracy w moim środowisku.

Ten kod umożliwia dostęp do wszystkich możliwych baz danych jednej instancji , a nie tylko jednej bazy danych.

Korzystam z dwóch tabel tymczasowych, aby zebrać odpowiednie dane, a następnie zrzucam wyniki do jednej tabeli „na żywo”.

Zwracane dane to: nazwa_bazy_danych, nazwa_bazy_danych, wiersze (w tabeli), dane (wydaje się, że rozmiar tabeli w kilobajtach), dane wejściowe (uważam, że jest to przydatne, gdybym wiedział, kiedy ostatnio uruchomiłem skrypt).

Wadą tego kodu jest to, że pole „data” nie jest przechowywane jako int (znaki „KB” są przechowywane w tym polu), a to byłoby przydatne (ale nie całkowicie konieczne) do sortowania.

Mam nadzieję, że ten kod pomaga komuś tam i oszczędza mu trochę czasu!

CREATE PROCEDURE [dbo].[usp_getAllDBTableSizes]

AS
BEGIN
   SET NOCOUNT OFF

   CREATE TABLE #DatabaseTables([dbname] sysname,TableName sysname)
   CREATE TABLE #AllDatabaseTableSizes(Name sysname,[rows] VARCHAR(18), reserved VARCHAR(18), data VARCHAR(18), index_size VARCHAR(18), unused VARCHAR(18))

   DECLARE @SQL nvarchar(4000)
   SET @SQL='select ''?'' AS [Database], Table_Name from [?].information_schema.tables WHERE TABLE_TYPE = ''BASE TABLE'' '

   INSERT INTO #DatabaseTables(DbName, TableName)
      EXECUTE sp_msforeachdb @Command1=@SQL

   DECLARE AllDatabaseTables CURSOR LOCAL READ_ONLY FOR   
   SELECT TableName FROM #DatabaseTables

   DECLARE AllDatabaseNames CURSOR LOCAL READ_ONLY FOR   
   SELECT DBName FROM #DatabaseTables

   DECLARE @DBName sysname  
   OPEN AllDatabaseNames  

   DECLARE @TName sysname
   OPEN AllDatabaseTables  

   WHILE 1=1 BEGIN 
      FETCH NEXT FROM AllDatabaseNames INTO @DBName  
      FETCH NEXT FROM AllDatabaseTables INTO @TName 
      IF @@FETCH_STATUS<>0 BREAK  
      INSERT INTO #AllDatabaseTableSizes
         EXEC ( 'EXEC ' + @DBName + '.dbo.sp_spaceused ' + @TName) 

   END 

   --http://msdn.microsoft.com/en-us/library/aa175920(v=sql.80).aspx
   INSERT INTO rsp_DatabaseTableSizes (DatabaseName, name, [rows], data)
      SELECT   [dbname], name, [rows],  data FROM #DatabaseTables
      INNER JOIN #AllDatabaseTableSizes
      ON #DatabaseTables.TableName = #AllDatabaseTableSizes.Name
      GROUP BY [dbname] , name, [rows],  data
      ORDER BY [dbname]
   --To be honest, I have no idea what exact duplicates we are dropping
    -- but in my case a near enough approach has been good enough.
   DELETE FROM [rsp_DatabaseTableSizes]
   WHERE name IN 
      ( 
      SELECT name 
      FROM [rsp_DatabaseTableSizes]
      GROUP BY name
      HAVING COUNT(*) > 1
      )

   DROP TABLE #DatabaseTables
   DROP TABLE #AllDatabaseTableSizes

   CLOSE AllDatabaseTables  
   DEALLOCATE AllDatabaseTables  

   CLOSE AllDatabaseNames  
   DEALLOCATE AllDatabaseNames      
END

--EXEC [dbo].[usp_getAllDBTableSizes] 

W razie potrzeby tabela rsp_DatabaseTableSizes została utworzona poprzez:

CREATE TABLE [dbo].[rsp_DatabaseSizes](
    [DatabaseName] [varchar](1000) NULL,
    [dbSize] [decimal](15, 2) NULL,
    [DateUpdated] [smalldatetime] NULL
) ON [PRIMARY]

GO

1

Jako proste rozszerzenie odpowiedzi marc_s (tej, która została zaakceptowana), jest dostosowywane tak, aby zwracało liczbę kolumn i pozwalało na filtrowanie:

SELECT *
FROM
(

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    COUNT(DISTINCT c.COLUMN_NAME) as ColumnCount,
    SUM(a.total_pages) * 8 AS TotalSpaceKB, 
    (SUM(a.used_pages) * 8) AS UsedSpaceKB, 
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
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
INNER JOIN
    INFORMATION_SCHEMA.COLUMNS c ON t.NAME = c.TABLE_NAME
LEFT OUTER 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
GROUP BY 
    t.Name, s.Name, p.Rows
) AS Result

WHERE
    RowCounts > 1000
    AND ColumnCount > 10
ORDER BY 
    UsedSpaceKB DESC

Po dołączeniu do tabeli Kolumny nie masz już odpowiedniego obszaru tabel. Zewnętrzne zastosowanie będzie poprawką.
dreamca4er

0

W odpowiedzi na powyższą odpowiedź @Mark dodano @ updateusage = 'true', aby wymusić najnowsze statystyki wielkości ( https://msdn.microsoft.com/en-us/library/ms188776.aspx ):

        SET NOCOUNT ON
        DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
        DECLARE @cmd1 varchar(500)
        SET @cmd1 = 'exec sp_spaceused @objname =''?'', @updateusage =''true'' '

        INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
        EXEC sp_msforeachtable @command1=@cmd1 
SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC

0

Oto przykładowe zapytanie, aby uzyskać tabele większe niż 1 GB uporządkowane według wielkości malejącej.

USE YourDB
GO

DECLARE @Mult float = 8
SET @Mult = @Mult / POWER(2, 20) -- Use POWER(2, 10) for MBs

; WITH CTE AS
(
SELECT
    i.object_id,
    Rows = MAX(p.rows),
    TotalSpaceGB = ROUND(SUM(a.total_pages) * @Mult, 0),
    UsedSpaceGB = ROUND(SUM(a.used_pages) * @Mult, 0)
FROM 
    sys.indexes i
JOIN
    sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE
    i.object_id > 255
GROUP BY
    i.object_id
HAVING
    SUM(a.total_pages) * @Mult > 1
)
SELECT 
    SchemaName = s.name,
    TableName = t.name,
    c.TotalSpaceGB,
    c.UsedSpaceGB,
    UnusedSpaceGB = c.TotalSpaceGB - c.UsedSpaceGB,
    [RowCount] = c.Rows
FROM 
    CTE c
JOIN    
    sys.tables t ON t.object_id = c.object_id
JOIN
    sys.schemas s ON t.schema_id = s.schema_id
ORDER BY
    c.TotalSpaceGB DESC
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.