Taille de la table et de l'index dans SQL Server

90

Pouvons-nous avoir une requête SQL qui aidera essentiellement à visualiser les tailles de table et d'index dans SQl Server.

Comment SQL Server gère l'utilisation de la mémoire pour les tables / index?

Kamal Joshi
la source
1
Vous pouvez également trouver la procédure stockée sp_helpdbutile
Zack Burt
1
Il y a déjà des réponses à cela, mais j'utilise personnellement la requête dans ce lien: qualityofdata.com/2011/02/02/…
naiem

Réponses:

73

Le exec sp_spaceusedparamètre sans affiche le résumé de l'ensemble de la base de données. La solution foreachtable génère un ensemble de résultats par table - que SSMS ne pourra peut-être pas gérer si vous avez trop de tables.

J'ai créé un script qui collecte les informations de la table via sp_spaceusedet affiche un résumé dans un seul jeu d'enregistrements, trié par taille.

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
la source
4
Votre script ne gère que les tables du schéma «dbo». Si j'ai une table dans ma base de données avec un schéma «Audit», sp_spaceused doit être appelé comme ceci: exec sp_spaceused «Audit.Data». Le script doit donc être modifié pour lui donner le nom de la table précédé du nom du schéma (séparé par un point) pour qu'il renvoie des données sur les tables d'autres schémas.
Baodad
1
Bon point @Boadad ... ça devrait être une solution super facile. Remplacer le "select name from sysobjects where xtype = 'U'" par ceci devrait faire l'affaire: "select '[' + sc.name + ']. [' + S.name + ']' FROM sysobjects s ​​INNER JOIN sys .schemas sc ON s.uid = sc.schema_id où s.xtype = 'U' "Excellent script, merci!
DCaugs
au lieu d'utiliser une table temporaire, pouvons-nous insérer des données dans une autre table qui n'est pas temporaire?
Prabhakar
@PrabhakarPandey Bien sûr, supprimez simplement le fichier #.
Racer SQL
120

sp_spaceused vous donne la taille de tous les index combinés.

Si vous voulez la taille de chaque index pour une table, utilisez l'une de ces deux requêtes:

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

Les résultats sont généralement légèrement différents, mais à moins de 1%.

Rob Garrison
la source
La première requête comprend des clés primaires, ce qui est un peu déroutant pour plusieurs raisons.
quillbreaker
La deuxième requête Msg 102, Level 15, State 1, Line 5 - Incorrect syntax near '('.me jette , mais je ne vois aucun problème avec la syntaxe. Une idée?
Oliver
Oliver, quelle version utilisez-vous? Cela fonctionne tel quel pour moi en 2008R2 et 2012.
Rob Garrison
24

Sur SQL 2012, obtenir ces informations au niveau d'une table est devenu délicieusement simple:

SQL Management Studio -> Faites un clic droit sur Db -> Rapports -> Rapports standard -> Utilisation du disque par table!

Prendre plaisir

terrien42
la source
13
EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"
Ben R
la source
3
Si vous publiez des échantillons de code, XML ou de données, VEUILLEZ mettre en évidence ces lignes dans l'éditeur de texte et cliquer sur le bouton "exemples de code" ( { }) dans la barre d'outils de l'éditeur pour bien le formater et la mettre en évidence!
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
la source
3

Voici une version plus compacte de la réponse la plus réussie:

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
la source
3

ça fait longtemps que ce post a été créé mais je voulais partager mon script:

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

cela fonctionne pour:

  • SQL Server (à partir de 2008)
  • Inclut des informations pour toutes les tables par base de données actuelle
jthalliens
la source
0

Il existe une procédure stockée étendue sp_spaceusedqui extrait ces informations. Il est assez compliqué de le faire à partir du dictionnaire de données, mais Ce lien se déploie vers un script qui le fait. Cette question de stackoverflow contient des informations sur les structures de données sous-jacentes que vous pouvez utiliser pour construire des estimations de la taille des tables et des index pour la planification des capacités.

ConcernedOfTunbridgeWells
la source
0

Cette requête provient de deux autres réponses:

Obtenir la taille de toutes les tables de la base de données

Comment trouver les objets les plus volumineux dans une base de données SQL Server?

, mais j'ai amélioré cela pour qu'il soit universel. Il utilise un sys.objectsdictionnaire:

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
la source