Mostra la ripartizione dei dati e dell'utilizzo del disco per tabella


9

Ho un database SQL Server 2008 R2 utilizzato da diversi programmi distribuiti.

Domanda: esiste un modo semplice per visualizzare quanto spazio consuma ogni tabella, per tutte le tabelle nel database, e distinguere lo spazio logico dallo spazio su disco?

Se utilizzo SSMS (Management Studio), le proprietà di archiviazione visualizzate per il database indicano 167 MB con 3 MB "disponibili" (circa la dimensione giusta, ma sono preoccupato per i 3 MB disponibili - è un limite di cui preoccuparsi , supponendo che io sappia che ho abbastanza spazio su disco?)

Posso approfondire ogni tavolo, ma ci vuole un'eternità per farlo.

So che posso scrivere le mie query e testare in giro, ma mi piacerebbe sapere se esiste già un modo semplice (integrato?) Per farlo.

Risposte:


13

In SSMS, fare clic con il tasto destro del mouse sul database e selezionare "Rapporti", "Rapporti standard", "Utilizzo del disco per tabella". Ti dirà la dimensione totale, la dimensione dei dati, la dimensione dell'indice e la dimensione non utilizzata per ogni tabella (nonché il conteggio delle righe).


1
Non l'avevo mai visto prima e mi piaceva meglio dello script - tranne che su alcuni database fallisce perché non ho l'autorizzazione "VISUALIZZA DATABASE STATE" - ma lo script funzionerà in quel caso. Vai a capire!
Chris Woodruff,

10

E 'stato risposto su Stack Overflow:

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 
    t.Name

5

La query collegata e copiata da @Nelson non è precisa: ignora viste indicizzate, indici full-text, indici XML, ecc.

Se vuoi una query che includa tutto senza eseguire sp_spaceusedtramite sp_MSForEachTable, allora ho già pubblicato due varianti di esso (uno qui su DBA.StackExchange e l'altro su StackOverflow), quindi non li copierò qui:


4

Solo per divertimento, ecco una query che genererà gli stessi dati del report nella risposta di nateirvin

create table #disk_usage
(
    name varchar(128)
    ,rows varchar(20)
    ,reserved varchar(20)
    ,data varchar(20)
    ,index_size varchar(20)
    ,unused varchar(20)
);

exec sp_msforeachtable 'insert into #disk_usage exec sp_spaceused [?]'

select SCHEMA_NAME(st.schema_id) + '.' + du.name 'Table Name'
 ,du.rows '# Records'
 ,du.reserved 'Reserved (KB)'
 ,du.data 'Data (KB)'
 ,du.index_size 'Indexes (KB)'
 ,du.unused 'Unused (KB)'
 from #disk_usage du
left join sys.tables st
on du.name = st.name
order by cast(left(reserved, len(reserved) - 3) as bigint) desc;

drop table #disk_usage

Va bene, perché mi odio davvero , ho scritto una query che genererà i risultati del rapporto, lo formatterà come una tabella HTML e lo invierà come e-mail. L'abbinamento dei colori di sfondo del report viene lasciato come esercizio per il lettore.

declare @subject nvarchar(25) = 'Disk Usage by Top Tables';

declare @recipients nvarchar(25) = 'mailbox@example.com';

create table #disk_usage
(
    name varchar(128)
    ,rows varchar(20)
    ,reserved varchar(20)
    ,data varchar(20)
    ,index_size varchar(20)
    ,unused varchar(20)
);

exec sp_msforeachtable 'insert into #disk_usage EXEC sp_spaceused [?]'

declare @body nvarchar(max) = 
'<table cellspacing="0">
    <thead>
        <tr>
            <th>Table Name</th>
            <th># Rows</th>
            <th>Reserved</th>
            <th>Data</th>
            <th>Indexes</th>
            <th>Unused</th>
        </tr>
    </thead>
';

set @body = @body + cast (
    (select '<td style="border: 1px solid black; padding: 2px">' + SCHEMA_NAME(s.schema_id) + '.' + t.name + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + rtrim(ltrim(t.rows)) + ' Rows </td>' -- for some reason this was generating a bunch of extra white space and I'm not going to bother to figure out why
     ,'<td style="border: 1px solid black; padding: 2px">' + t.reserved + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.data + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.index_size + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.unused + '</td>'
     from #disk_usage t
    left join sys.tables s
    on t.name = s.name
    order by cast(left(reserved, len(reserved) - 3) as bigint) desc
    for xml path ('tr'))
as nvarchar(max));

set @body = replace(replace(@body, '&lt;', '<'), '&gt;', '>')
set @body = @body + '</table>'

exec msdb.dbo.sp_send_dbmail 
@profile_name='A Database Mail Profile On The Target Server', 
@recipients=@recipients, 
@subject=@subject,
@body=@body,
@body_format='HTML'

drop table #disk_usage

1
Wow! L'ultimo pezzo di lavoro auto-odiato è meraviglioso (per gli altri ;-))! Grazie per averlo aggiunto. Mi dispiace di avere un solo voto da dare a questa risposta ...
Dronz

1
:) Ho pensato che se avessi dovuto sopportare il dolore di farlo, il minimo che posso fare è salvare qualcun altro dallo stesso destino.
MikeTheLiar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.