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

1271

J'ai hérité d'une base de données SQL Server assez volumineuse. Il semble prendre plus de place que je ne le pense, compte tenu des données qu'il contient.

Existe-t-il un moyen simple de déterminer combien d'espace sur le disque chaque table consomme?

Eric
la source
à quels rôles avez-vous accès? Êtes-vous le DBA, ou est-ce géré par un hébergeur, un client ou similaire?
Rob Allen,
doublon possible de la taille
Joe Stefanelli
@RobAllen J'ai un accès complet à la base de données, donc un script qui nécessite n'importe quel rôle est suffisant.
Eric
Pour Azure, j'ai utilisé cela
Irf

Réponses:

2594
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
marc_s
la source
7
Question idiote, mais est-il possible que cette requête puisse provoquer un verrouillage de ligne?
GEMI
7
Les index utilisent également de l'espace, et l'espace utilisé par les index peut être trouvé avec cette requête ci-dessous.
Jens Frandsen
6
Votre script a des problèmes avec les index filtrés: pour chaque index filtré pour une table donnée, je vois une ligne supplémentaire avec le nom de cette table dans les résultats. Les "RowCounts" de chacune de ces lignes supplémentaires correspondent au nombre de lignes couvertes par l'un des index filtrés. (on Sql2012)
Akos Lukacs
37
@Todd: certaines personnes veulent qu'il a ordonné cette façon - d' autres veulent par nom de la table - faites votre choix, adapter le code au besoin ....
marc_s
12
Si vos tables sont partitionnées, elles apparaissent plusieurs fois sans aucune indication de ce qui se passe. Vous pouvez ajouter p.partition_number à la liste de sélection ou vous pouvez SUM (p.Rows) et le supprimer du groupe par.
PRMan
561

Si vous utilisez SQL Server Management Studio (SSMS), au lieu d'exécuter une requête ( qui dans mon cas a renvoyé des lignes en double ), vous pouvez exécuter un rapport standard

  1. Clic droit sur la base de données
  2. Accédez à Rapports> Rapports standard> Utilisation du disque par table

Remarque: Le niveau de compatibilité de la base de données doit être défini sur 90 ou plus pour que cela fonctionne correctement. Voir http://msdn.microsoft.com/en-gb/library/bb510680.aspx

Kevin Brydon
la source
54
Dans Management Studio 2012, vous pouvez faire: Afficher les détails de l'explorateur d'objets (F7) et accéder aux "Tables" dans l'Explorateur d'objets. Dans Détails, cliquez avec le bouton droit sur l'en-tête et sélectionnez les colonnes de taille.
ValGe
3
pour avoir conseillé de nouvelles fonctionnalités avec SSMS 2012. Pour nous, les anciens, nous ne l'avons jamais eu. Nous l'avons donc fait à l'ancienne TSQL :)
GoldBishop
3
Croyez-le ou non, parfois de simples mortels (développeurs) aimeraient voir ces informations et nous n'avons pas les autorisations pour utiliser le rapport intégré, mais nous pouvons exécuter le TSQL dans la réponse acceptée. :) Pour info (BTW, j'ai toujours voté pour votre réponse)
Andrew Steitz
8
Ne semble pas être présent dans Azure SQL :-(
Simon_Weaver
1
Je sais que ce n'est pas grave, mais, s'il vous plaît, vous repoussez simplement les groupes marginalisés de l'ingénierie et de la technologie avec ce raisonnement qui se répète partout. Vous devriez apprendre les deux, mais vous ne devriez pas non plus châtier les gens pour qu'ils utilisent des utilitaires permettant de gagner du temps pour travailler plus intelligemment et plus rapidement. (Bien que SSMS semble être un "utilitaire de ralentissement" parfois ...: X) Personnellement, les lectures des données tabulaires sont généralement plus claires dans une interface graphique, bien que les outils construits par Microsoft aient tendance à être les exceptions pour tout ce qui est lié à l'interface utilisateur.
Julia McGuigan
102

sp_spaceused peut vous obtenir des informations sur l'espace disque utilisé par une table, une vue indexée ou la base de données entière.

Par exemple:

USE MyDatabase; GO

EXEC sp_spaceused N'User.ContactInfo'; GO

Cela rapporte les informations d'utilisation du disque pour la table ContactInfo.

Pour l'utiliser simultanément pour toutes les tables:

USE MyDatabase; GO

sp_msforeachtable 'EXEC sp_spaceused [?]' GO

Vous pouvez également obtenir l'utilisation du disque à partir du clic droit sur la fonctionnalité Rapports standard de SQL Server. Pour accéder à ce rapport, accédez à l'objet serveur dans l'Explorateur d'objets, descendez jusqu'à l'objet Bases de données, puis cliquez avec le bouton droit sur une base de données. Dans le menu qui apparaît, sélectionnez Rapports, puis Rapports standard, puis "Utilisation du disque par partition: [DatabaseName]".

Essieu
la source
3
C'est bien, bien que l'utilisation de sp_msforeachtableSSMS puisse facilement déclencher un System.OutOfMemoryExceptionsi vous avez un grand nombre de tables, il peut donc être préférable d'utiliser une table temporaire pour stocker les résultats.
syneticon-dj
1
Le principal problème que je peux voir avec sp_spacedused est qu'il semble renvoyer les données dans un format lisible par l'homme (par exemple, dans la colonne «réservé» dans mon cas, il contenait «152 Ko»). Je suppose que cela passera en Mo / Go, le cas échéant. Ceci est clairement utile dans de nombreuses situations, mais pas si vous devez appliquer une logique basée sur la taille, ou si vous souhaitez comparer des valeurs ou autre chose. J'ai cherché un moyen de désactiver cela, mais je n'ai pas pu en
trouver
55

Voici une autre méthode: à l'aide de SQL Server Management Studio , dans l' Explorateur d'objets , accédez à votre base de données et sélectionnez Tables

entrez la description de l'image ici

Ouvrez ensuite les détails de l'explorateur d'objets (en appuyant sur F7 ou en allant dans Affichage-> Détails de l'explorateur d'objets ). Dans la page de détails de l'explorateur d'objets, cliquez avec le bouton droit sur l'en-tête de colonne et activez les colonnes que vous souhaitez voir dans la page. Vous pouvez également trier les données par n'importe quelle colonne.

entrez la description de l'image ici

Moineau
la source
Oui, SSMS dans Azure manque de fonctionnalités par rapport à la version locale.
Sparrow
@batmaci Je ne sais pas si cela fonctionnait du tout lorsque vous avez fait votre commentaire sur les bases de données Azure SQL, mais cela semble au moins partiellement fonctionner maintenant dans les versions récentes de SSMS. Pour moi, il semble que la requête pour les métadonnées de table expire, mais avant cela, elle semble renvoyer quelques (3-10) tables, y compris (de manière fiable) la table sélectionnée. Sélectionnez une table et cliquez sur Actualiser pour voir la table souhaitée si elle ne s'affiche pas.
pcdev
Azure n'est pas "vrai" SQL Server (ha ha)
Reversed Engineer
J'ai utilisé ceci pour Azure, merci avec un (plus un),
Irf
Vous pouvez également exporter la liste dans un fichier CSV en utilisant un utilitaire comme NirSoft SysExporter: nirsoft.net/utils/sysexp.html
maximum
39

Après quelques recherches, je n'ai pas pu trouver un moyen facile d'obtenir des informations sur tous les tableaux. Il existe une procédure stockée pratique nommée sp_spaceused qui retournera tout l'espace utilisé par la base de données. S'il est fourni avec un nom de table, il renvoie l'espace utilisé par cette table. Toutefois, les résultats renvoyés par la procédure stockée ne sont pas triables, car les colonnes sont des valeurs de caractères.

Le script suivant générera les informations que je recherche.

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
Eric
la source
Après avoir vu ce qui précède en utilisant foreach et le SP allait écrire quelque chose comme ça, heureux d'avoir fait défiler vers le bas pour voir que cela m'a fait gagner un peu de temps.
Brad
37
 exec  sp_spaceused N'dbo.MyTable'

Pour tous les tableaux, utilisez .. (ajout des commentaires de Paul)

exec sp_MSForEachTable 'exec sp_spaceused [?]'
Royi Namir
la source
5
Sneaky - vous avez changé exec sp_helpdbce qui ne montre rien sur les tables, exec sp_spaceusedce qui le fait - mais seulement pour une table à la fois ... cela ne vous donne pas un aperçu de quelles tables vous avez et combien de lignes elles ont et comment beaucoup d'espace qu'ils occupent.
marc_s
4
exec sp_MSForEachTable 'exec sp_spaceused [?]'
Paul
27

Les requêtes ci-dessus sont utiles pour trouver la quantité d'espace utilisée par la table (index inclus), mais si vous souhaitez comparer la quantité d'espace utilisée par les index sur la table, utilisez cette requête:

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
Jens Frandsen
la source
Quelle est la raison pour laquelle la somme de la colonne Indexsize (KB) pour une table particulière est en désaccord avec l'index_size de sp_spaceused?
Derek
@Derek Correction de sa réponse en ajoutant where [i].[is_primary_key] = 0. Maintenant, les tailles doivent correspondre.
CodeAngry
Merci, mais cela ne fonctionne pas non plus. J'ai une (très petite) base de données de test, la table d'intérêt a deux index - un index cluster principal sur une colonne et un index non cluster sur deux des autres colonnes. Cette requête indique que chacun d'eux utilise 16 Ko, mais sp_spaceused indique que l'utilisation totale de l'index est de 24 Ko. Une partie de ma confusion est la suivante: en comparant cette requête au "UsedSpaceKB" de la réponse acceptée, je ne vois pas de réelle différence. Mêmes jointures, il manque juste l'ajout de sys.tables. Suis-je en train de manquer quelque chose ou cette requête est-elle intrinsèquement cassée?
Derek
J'ai de grandes bases de données. Et les tailles correspondent à sp_spaceused. Je mesure les Go, donc quelques mégas qui ne correspondent pas, ce n'est pas beaucoup. Je me fiche des tailles exactes, juste une idée.
CodeAngry
14

Si vous devez calculer exactement les mêmes nombres, qui se trouvent sur la page 'propriétés de la table - stockage' dans SSMS, vous devez les compter avec la même méthode que celle utilisée dans SSMS (fonctionne pour SQL Server 2005 et supérieur ... et aussi fonctionne correctement pour les tables avec des champs LOB - car le simple fait de compter "used_pages" n'est pas suffisant pour afficher une taille d'index précise):

;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
sqladmin
la source
14

Extension à la réponse @xav qui traitait les partitions de table pour obtenir la taille en Mo et Go. Testé sur SQL Server 2008/2012 (commenté une ligne où 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
Santhoshkumar KB
la source
également un meilleur ordre de tri.
Pxtl
Cela devrait être la meilleure réponse.
Baodad
14

Pour Azure, j'ai utilisé ceci:

Vous devriez avoir SSMS v17.x

J'ai utilisé;

entrez la description de l'image ici

Avec cela, comme l' a mentionné l' utilisateur Sparrow :

Ouvrez votre Databases> et sélectionnez Tableaux ,
puis appuyez sur la touche F7 Vous devriez voir le row count
comme: entrez la description de l'image ici

SSMS ici est connecté aux bases de données Azure

Irf
la source
3
F7 est fortement sous-utilisé.
cskwg
1
Je n'avais aucune idée que cela existait, j'ai un peu honte de moi: p Merci!
lollancf37
Il y a un problème avec les tables optimisées en mémoire, (je viens de tester après avoir vu ce post :)
Amirreza
11

Nous utilisons le partitionnement de table et avons eu quelques problèmes avec les requêtes fournies ci-dessus en raison d'enregistrements en double.

Pour ceux qui en ont besoin, vous trouverez ci-dessous la requête exécutée par SQL Server 2014 lors de la génération du rapport «Utilisation du disque par table». Je suppose que cela fonctionne également avec les versions précédentes de SQL Server.

Il fonctionne comme un charme.

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
xav
la source
Merci pour un script qui correspond à la façon dont SSMS le fait et gère correctement les partitions.
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
marque
la source
8

Un petit changement sur la réponse de Mar_c , puisque je reviens si souvent sur cette page, ordonnée par la plupart des lignes en premier:

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 
Joel Harkes
la source
5

Cela vous donnera les tailles et les nombres d'enregistrements pour chaque table.

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
William Walseth
la source
2
Si vous publiez du code, du XML ou des échantillons de données, VEUILLEZ surligner ces lignes dans l'éditeur de texte et cliquez sur le bouton "échantillons de code" ( { }) dans la barre d'outils de l'éditeur pour bien le mettre en forme et la syntaxe, mettez-le en surbrillance!
marc_s
4

Pour obtenir toutes les tailles de table dans une base de données, vous pouvez utiliser cette requête:

Exec sys.sp_MSforeachtable ' sp_spaceused "?" '

Et vous pouvez le changer pour insérer tout le résultat dans la table temporaire et ensuite sélectionner dans la table temporaire.

Insert into #TempTable Exec sys.sp_MSforeachtable ' sp_spaceused "?" ' 
Select * from #TempTable
Ardalan Shahgholi
la source
3

À partir d'une invite de commande utilisant OSQL :

OSQL -E -d <*databasename*> -Q "exec sp_msforeachtable 'sp_spaceused [?]'" > result.txt
user4658783
la source
3

Voici un moyen d'obtenir rapidement toutes les tailles de tableaux avec les étapes suivantes:

  1. Écrivez les commandes T-SQL données pour répertorier toutes les tables de base de données:

    select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
  2. Copiez maintenant la liste des tables de base de données et copiez-la dans une nouvelle fenêtre d'analyseur de requêtes

    exec sp_spaceused table1
    exec sp_spaceused table2
    exec sp_spaceused table3
    exec sp_spaceused table4
    exec sp_spaceused table5
  3. Dans l' analyseur de requêtes SQL , sélectionnez dans la barre d'outils supérieure l'option Résultats vers le fichier ( Ctrl+ Shift+ F).

  4. Maintenant, appuyez enfin sur le bouton Exécuter rouge marqué dans la barre d'outils ci-dessus .

  5. La taille de la base de données de toutes les tables est désormais stockée dans un fichier sur votre ordinateur.

    Entrez la description de l'image ici

Anjan Kant
la source
2

J'ai ajouté quelques colonnes supplémentaires au-dessus de la réponse de 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
Alan Cardoso
la source
1

Ma publication n'est pertinente que pour SQL Server 2000 et a été testée pour fonctionner dans mon environnement.

Ce code accède à toutes les bases de données possibles d'une seule instance , pas seulement à une seule base de données.

J'utilise deux tables temporaires pour aider à collecter les données appropriées, puis vider les résultats dans une table «en direct».

Les données renvoyées sont: DatabaseName, DatabaseTableName, Rows (dans le tableau), data (la taille du tableau en Ko semble-t-il), les données d'entrée (je trouve cela utile pour savoir quand j'ai exécuté le script pour la dernière fois).

La chute de ce code est que le champ «données» n'est pas stocké en tant qu'int (les caractères «KB» sont conservés dans ce champ), et cela serait utile (mais pas totalement nécessaire) pour le tri.

Espérons que ce code aide quelqu'un là-bas et lui fait gagner du temps!

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] 

Si vous avez besoin de savoir, la table rsp_DatabaseTableSizes a été créée via:

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

GO
Andrew
la source
1

En tant que simple extension de la réponse de marc_s (celle qui a été acceptée), elle est ajustée pour renvoyer le nombre de colonnes et permettre le filtrage:

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
Zach Smith
la source
Une fois que vous avez rejoint la table Colonnes, vous n'avez plus le bon espace table. L'application externe sera la solution.
dreamca4er
0

Riffant sur la réponse @Mark ci-dessus, a ajouté le @ updateusage = 'true' pour forcer les dernières statistiques de taille ( 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
Chris Smith
la source
0

Voici un exemple de requête pour obtenir des tableaux supérieurs à 1 Go classés par taille décroissante.

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