Aufschlüsselung der Daten und der Datenträgerverwendung nach Tabelle

9

Ich habe eine SQL Server 2008 R2-Datenbank, die von mehreren bereitgestellten Programmen verwendet wird.

Frage: Gibt es eine einfache Möglichkeit, anzuzeigen, wie viel Speicherplatz jede Tabelle für alle Tabellen in der Datenbank belegt, und logischen Speicherplatz von Speicherplatz zu unterscheiden?

Wenn ich SSMS (Management Studio) verwende, lauten die für die Datenbank angezeigten Speichereigenschaften 167 MB, wobei 3 MB "verfügbar" sind (ungefähr die richtige Größe, aber ich bin besorgt über die verfügbaren 3 MB - ist dies eine zu bedenkende Grenze vorausgesetzt, ich weiß, dass ich genug Speicherplatz habe?)

Ich kann in jeden Tisch bohren, aber das dauert ewig.

Ich weiß, dass ich meine eigenen Abfragen schreiben und testen kann, aber ich würde gerne wissen, ob es bereits eine einfache (integrierte?) Möglichkeit gibt, dies zu tun.

Dronz
quelle

Antworten:

13

Klicken Sie in SSMS mit der rechten Maustaste auf die Datenbank und gehen Sie zu "Berichte", "Standardberichte", "Datenträgerverwendung nach Tabelle". Hier erfahren Sie die Gesamtgröße, die Datengröße, die Indexgröße und die nicht verwendete Größe für jede Tabelle (sowie die Zeilenanzahl).

Nateirvin
quelle
1
Ich hatte das noch nie gesehen und es gefällt mir besser als das Skript - außer dass es in einigen Datenbanken fehlschlägt, weil ich nicht die Berechtigung "DATABASE STATE ANZEIGEN" habe - aber das Skript funktioniert in diesem Fall. Stelle dir das vor!
Chris Woodruff
10

Es wurde auf Stapelüberlauf beantwortet :

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
Nelz
quelle
5

Die mit @Nelson verknüpfte und von @Nelson kopierte Abfrage ist ungenau: Indizierte Ansichten, Volltextindizes, XML-Indizes usw. werden ignoriert.

Wenn Sie eine Abfrage wünschen, die alles enthält, ohne sp_spaceusedüber ausgeführt zu werden sp_MSForEachTable, habe ich bereits zwei Variationen davon veröffentlicht (eine hier auf DBA.StackExchange und die andere auf StackOverflow), damit ich sie hier nicht kopiere:

Solomon Rutzky
quelle
4

Nur zum Spaß, hier ist eine Abfrage, die die gleichen Daten wie der Bericht in Nateirvins Antwort generiert

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

Okay, weil ich mich selbst wirklich hasse, habe ich eine Abfrage geschrieben, die die Ergebnisse des Berichts generiert, ihn als HTML-Tabelle formatiert und als E-Mail sendet. Das Abgleichen der Hintergrundfarben des Berichts bleibt dem Leser als Übung.

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

declare @recipients nvarchar(25) = '[email protected]';

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
MikeTheLiar
quelle
1
Beeindruckend! Das letzte Stück selbstverachtender Arbeit ist wunderbar (für andere ;-))! Danke, dass du das hinzugefügt hast. Ich bedauere, dass ich nur eine Gegenstimme zu dieser Antwort habe ...
Dronz
1
:) Ich dachte mir, wenn ich den Schmerz durchmachen müsste, könnte ich zumindest jemand anderen vor dem gleichen Schicksal retten.
MikeTheLiar