Tabellen- und Indexgröße in SQL Server

90

Können wir eine SQL-Abfrage haben, die im Grunde beim Anzeigen von Tabellen- und Indexgrößen in SQl Server hilft?

Wie verwaltet SQL Server die Speichernutzung für Tabellen / Indizes?

Kamal Joshi
quelle
1
Sie können auch die gespeicherte Prozedur sp_helpdbnützlich finden
Zack Burt
1
Es gibt bereits Antworten darauf, aber ich persönlich benutze die Abfrage in diesem Link: Qualityofdata.com/2011/02/02/…
Naiem

Antworten:

73

Der exec sp_spaceusedParameter without zeigt die Zusammenfassung für die gesamte Datenbank. Die foreachtable-Lösung generiert eine Ergebnismenge pro Tabelle - die SSMS möglicherweise nicht verarbeiten kann, wenn Sie zu viele Tabellen haben.

Ich habe ein Skript erstellt , das die Tabelleninformationen über sammelt sp_spaceusedund eine Zusammenfassung in einem einzelnen Datensatz nach Größe sortiert anzeigt.

create table #t
(
  name nvarchar(128),
  rows varchar(50),
  reserved varchar(50),
  data varchar(50),
  index_size varchar(50),
  unused varchar(50)
)

declare @id nvarchar(128)
declare c cursor for
select '[' + sc.name + '].[' + s.name + ']' FROM sysobjects s INNER JOIN sys.schemas sc ON s.uid = sc.schema_id where s.xtype='U'

open c
fetch c into @id

while @@fetch_status = 0 begin

  insert into #t
  exec sp_spaceused @id

  fetch c into @id
end

close c
deallocate c

select * from #t
order by convert(int, substring(data, 1, len(data)-3)) desc

drop table #t
devio
quelle
4
Ihr Skript verarbeitet nur Tabellen im Schema 'dbo'. Wenn meine Datenbank eine Tabelle mit dem Schema 'Audit' enthält, muss sp_spaceused wie folgt aufgerufen werden: exec sp_spaceused 'Audit.Data'. Daher muss das Skript geändert werden, um den Tabellennamen einzugeben, dem der Schemaname vorangestellt ist (durch einen Punkt getrennt), damit Daten zu Tabellen aus anderen Schemas zurückgegeben werden können.
Baodad
1
Guter Punkt @Boadad ... das sollte eine super einfache Lösung sein. Das Ersetzen des "Namen aus Sysobjekten auswählen, wobei xtype = 'U'" durch diesen sollte den folgenden Trick ausführen: "Wählen Sie '[' + sc.name + ']. [' + S.name + ']' FROM sysobjects s ​​INNER JOIN sys .schemas sc ON s.uid = sc.schema_id wobei s.xtype = 'U' "Tolles Skript, danke!
DCaugs
Können wir anstelle einer temporären Tabelle Daten in eine andere Tabelle einfügen, die nicht temporär ist?
Prabhakar
@PrabhakarPandey Sicher, entfernen Sie einfach die #.
Racer SQL
119

sp_spaceused gibt Ihnen die Größe aller Indizes zusammen.

Wenn Sie die Größe jedes Index für eine Tabelle möchten, verwenden Sie eine dieser beiden Abfragen:

SELECT
    i.name                  AS IndexName,
    SUM(s.used_page_count) * 8   AS IndexSizeKB
FROM sys.dm_db_partition_stats  AS s 
JOIN sys.indexes                AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
WHERE s.[object_id] = object_id('dbo.TableName')
GROUP BY i.name
ORDER BY i.name

SELECT
    i.name              AS IndexName,
    SUM(page_count * 8) AS IndexSizeKB
FROM sys.dm_db_index_physical_stats(
    db_id(), object_id('dbo.TableName'), NULL, NULL, 'DETAILED') AS s
JOIN sys.indexes AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
GROUP BY i.name
ORDER BY i.name

Die Ergebnisse sind normalerweise leicht unterschiedlich, liegen jedoch innerhalb von 1%.

Rob Garrison
quelle
Die erste Abfrage enthält Primärschlüssel, was aus mehreren Gründen etwas verwirrend ist.
Federbrecher
Die zweite Abfrage wirft Msg 102, Level 15, State 1, Line 5 - Incorrect syntax near '('.mich an, aber ich kann keine Probleme mit der Syntax sehen. Irgendeine Idee?
Oliver
Oliver, auf welcher Version läufst du? Es funktioniert wie es ist für mich in 2008R2 und 2012.
Rob Garrison
24

In SQL 2012 ist es sehr einfach geworden, diese Informationen auf Tabellenebene abzurufen:

SQL Management Studio -> Klicken Sie mit der rechten Maustaste auf Datenbank -> Berichte -> Standardberichte -> Datenträgerverwendung nach Tabelle!

Genießen

Erdling42
quelle
13
EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"
Ben R.
quelle
3
Wenn Sie Code-, XML- oder Datenbeispiele veröffentlichen, markieren Sie diese Zeilen BITTE im Texteditor und klicken Sie auf die Schaltfläche "Codebeispiele" ( { }) in der Editor-Symbolleiste, um sie gut zu formatieren und in der Syntax hervorzuheben!
marc_s
4
--Gets the size of each index for the specified table
DECLARE @TableName sysname = N'SomeTable';

SELECT i.name AS IndexName
      ,8 * SUM(s.used_page_count) AS IndexSizeKB
FROM sys.indexes AS i
    INNER JOIN sys.dm_db_partition_stats AS s 
        ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id
WHERE s.[object_id] = OBJECT_ID(@TableName, N'U')
GROUP BY i.name
ORDER BY i.name;

SELECT i.name AS IndexName
      ,8 * SUM(a.used_pages) AS IndexSizeKB
FROM sys.indexes AS i
    INNER JOIN sys.partitions AS p 
        ON i.[object_id]  = p.[object_id] AND i.index_id = p.index_id
    INNER JOIN sys.allocation_units AS a 
        ON p.partition_id = a.container_id
WHERE i.[object_id] = OBJECT_ID(@TableName, N'U')
GROUP BY i.name
ORDER BY i.name;
Alex
quelle
3

Hier ist eine kompaktere Version der erfolgreichsten Antwort:

create table #tbl(
  name nvarchar(128),
  rows varchar(50),
  reserved varchar(50),
  data varchar(50),
  index_size varchar(50),
  unused varchar(50)
)

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

select * from #tbl
    order by convert(int, substring(data, 1, len(data)-3)) desc

drop table #tbl
alpav
quelle
3

Es ist lange her seit der Erstellung für diesen Beitrag, aber ich wollte mein Skript teilen:

WITH CteIndex
AS
(
SELECT 
     reservedpages = (reserved_page_count)
     ,usedpages = (used_page_count)
     ,pages = (
            CASE
                WHEN (s.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
            )    
     ,s.object_id   
     ,i.index_id        
     ,i.type_desc AS IndexType
     ,i.name AS indexname
    FROM sys.dm_db_partition_stats s
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id   
)
SELECT DISTINCT
DB_NAME(DB_ID()) AS DatabaseName
,o.name AS TableName
,o.object_id
,ct.indexname
,ct.IndexType
,ct.index_id
, IndexSpace = LTRIM (STR ((CASE WHEN usedpages > pages THEN CASE WHEN ct.index_id < 2 THEN  pages ELSE (usedpages - pages) END ELSE 0 END) * 8, 15, 0) + ' KB')
FROM CteIndex ct
INNER JOIN sys.objects o ON o.object_id = ct.object_id
INNER JOIN sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL , NULL) ps ON ps.object_id = o.object_id
AND ps.index_id = ct.index_id
ORDER BY name ASC

es funktioniert für:

  • SQL Server (ab 2008)
  • Enthält Informationen für alle Tabellen pro aktueller Datenbank
jthalliens
quelle
0

Es gibt eine erweiterte gespeicherte Prozedur sp_spaceused, die diese Informationen herausgibt. Es ist ziemlich kompliziert, dies aus dem Datenwörterbuch heraus zu tun, aber dieser Link führt zu einem Skript, das dies tut. Diese Stackoverflow-Frage enthält einige Informationen zu den zugrunde liegenden Datenstrukturen, mit denen Sie Schätzungen der Tabellen- und Indexgrößen für die Kapazitätsplanung erstellen können.

ConcernedOfTunbridgeWells
quelle
0

Diese Abfrage stammt aus zwei anderen Antworten:

Ruft die Größe aller Tabellen in der Datenbank ab

Wie finde ich die größten Objekte in einer SQL Server-Datenbank?

, aber ich habe dies verbessert, um universell zu sein. Es verwendet sys.objectsWörterbuch:

SELECT 
    s.NAME as SCHEMA_NAME,
    t.NAME AS OBJ_NAME,
    t.type_desc as OBJ_TYPE,
    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.objects t
INNER JOIN
    sys.schemas s ON t.SCHEMA_ID = s.SCHEMA_ID 
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 
    s.NAME, t.NAME, t.type_desc, i.object_id, i.index_id, i.name 
ORDER BY
    sum(a.total_pages) DESC
;
Jakub P.
quelle