Obter tamanho de todas as tabelas no banco de dados

1271

Eu herdei um banco de dados do SQL Server bastante grande. Parece ocupar mais espaço do que eu esperava, dados os dados que ele contém.

Existe uma maneira fácil de determinar quanto espaço no disco cada tabela está consumindo?

Eric
fonte
a quais papéis você tem acesso? Você é o DBA ou é gerenciado por meio de um host, cliente ou similar?
Rob Allen
possível duplicata de tabela e índice tamanho em SQL Server
Joe Stefanelli
@ RobAllen Tenho acesso total ao banco de dados, portanto, um script que requer qualquer função é suficiente.
Eric
Para o Azure eu usei isso #
26419 Irf

Respostas:

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
fonte
7
Pergunta boba, mas é possível que essa consulta possa causar o bloqueio de linhas?
GEMI
7
Os índices também usam espaço, e a quantidade de espaço usada pelos índices pode ser encontrada com esta consulta abaixo.
Jens Frandsen
6
Seu script tem problemas com índices filtrados: para cada índice filtrado de uma determinada tabela, vejo uma linha extra com o nome dessa tabela nos resultados. O "RowCounts" de cada uma dessas linhas extras corresponde ao número de linhas cobertas por um dos índices filtrados. (em Sql2012)
Akos Lukacs
37
@Todd: algumas pessoas querem que ele ordenou que maneira - os outros querem que pelo nome da tabela - faça a sua escolha, adaptar o código conforme necessário ....
marc_s
12
Se suas tabelas forem particionadas, elas aparecerão várias vezes sem nenhuma indicação do que está acontecendo. Você pode adicionar p.partition_number à lista de seleção ou pode SUM (p.Rows) e removê-lo do grupo por.
PRMan
561

Se você estiver usando o SQL Server Management Studio (SSMS), em vez de executar uma consulta ( que no meu caso retornou linhas duplicadas ), poderá executar um relatório padrão

  1. Clique com o botão direito do mouse no banco de dados
  2. Navegue para Relatórios> Relatórios padrão> Uso do disco por tabela

Nota: O nível de compatibilidade do banco de dados deve ser definido como 90 ou superior para que funcione corretamente. Consulte http://msdn.microsoft.com/en-gb/library/bb510680.aspx

Kevin Brydon
fonte
54
No Management Studio 2012, você pode: Exibir detalhes do Explorador de objetos (F7) e navegar para "Tabelas" no Pesquisador de objetos. Em Detalhes, clique com o botão direito do mouse no cabeçalho e selecione as colunas de tamanho.
valge
3
por aconselhar novas funcionalidades com o SSMS 2012. Para nós, velhotes, nunca tivemos isso disponível. Então, nós apenas fizemos o caminho TSQL velho :)
GoldBishop
3
Acredite ou não, às vezes meros mortais (desenvolvedores) gostariam de ver essas informações e não temos permissão para usar o relatório incorporado, mas podemos executar o TSQL na resposta aceita. :) FYI (BTW, eu ainda votei na sua resposta) #
Andrew Steitz
8
Não parece estar presente no Azure SQL :-(
Simon_Weaver
1
Sei que não é sério, mas, por favor, você afasta grupos marginalizados da engenharia e da tecnologia, com essa linha de raciocínio sendo repetida em todos os lugares. Você deve aprender os dois, mas também não deve punir as pessoas por usarem utilitários que economizam tempo para trabalhar de maneira mais inteligente e rápida. (Embora o SSMS pareça às vezes ser um "utilitário de lentidão" ...: X) Pessoalmente, as leituras de dados tabulares geralmente são mais claras em uma GUI, embora as ferramentas criadas pela Microsoft tendam a ser as exceções para tudo relacionado à interface do usuário.
Julia McGuigan
102

O sp_spaceused pode fornecer informações sobre o espaço em disco usado por uma tabela, exibição indexada ou todo o banco de dados.

Por exemplo:

USE MyDatabase; GO

EXEC sp_spaceused N'User.ContactInfo'; GO

Isso relata as informações de uso do disco para a tabela ContactInfo.

Para usar isso para todas as tabelas de uma vez:

USE MyDatabase; GO

sp_msforeachtable 'EXEC sp_spaceused [?]' GO

Você também pode obter o uso do disco na funcionalidade Relatórios padrão do SQL Server. Para chegar a este relatório, navegue do objeto servidor no Pesquisador de Objetos, desça até o objeto Bancos de Dados e clique com o botão direito do mouse em qualquer banco de dados. No menu exibido, selecione Relatórios, Relatórios padrão e "Uso do disco por partição: [DatabaseName]".

Eixo
fonte
3
Isso é interessante, embora o uso sp_msforeachtableno SSMS possa facilmente desencadear um System.OutOfMemoryExceptioncaso você tenha um grande número de tabelas; portanto, seria uma idéia melhor usar uma tabela temporária para armazenar os resultados.
syneticon-dj
1
O principal problema que vejo com sp_spacedused é que ele parece retornar os dados em formato legível por humanos (por exemplo, na coluna 'reservada' no meu caso, tinha '152 KB'). Presumo que isso mudará para MB / GB, conforme apropriado. Isso é claramente útil em muitas situações, mas não se você precisar aplicar alguma lógica com base no tamanho ou desejar comparar valores ou o que for. Olhei para uma maneira de transformar isso fora, mas eu não poderia manchar um (estou usando o SQL Server 2005 :()
DarthPablo
55

Aqui está outro método: usando o SQL Server Management Studio , no Pesquisador de Objetos , acesse seu banco de dados e selecione Tabelas

insira a descrição da imagem aqui

Em seguida, abra os Detalhes do Pesquisador de Objetos (pressionando F7 ou indo para Exibir-> Detalhes do Pesquisador de Objetos ). Na página de detalhes do explorador de objetos, clique com o botão direito do mouse no cabeçalho da coluna e ative as colunas que você gostaria de ver na página. Você também pode classificar os dados por qualquer coluna.

insira a descrição da imagem aqui

Pardal
fonte
Sim, o SSMS no Azure não possui alguns recursos em comparação com a versão local.
Sparrow
@batmaci Não tenho certeza se isso estava funcionando quando você fez um comentário sobre os bancos de dados SQL do Azure, mas parece que pelo menos está parcialmente funcionando agora nas versões recentes do SSMS. Para mim, parece que a consulta dos metadados da tabela está atingindo o tempo limite, mas, antes disso, parece retornar algumas (3-10) tabelas, incluindo (de forma confiável) a tabela selecionada. Selecione uma tabela e clique em atualizar para ver a tabela desejada, se ela não for exibida.
Pcdev 16/05/19
O Azure não é o SQL Server "real" (ha ha)
Reversed Engineer
Eu usei isso para o Azure, obrigado com um (mais um),
Irf
Você também pode exportar a lista em um arquivo CSV usando um utilitário como o NirSoft SysExporter: nirsoft.net/utils/sysexp.html
Max
39

Após algumas pesquisas, não consegui encontrar uma maneira fácil de obter informações sobre todas as tabelas. Existe um procedimento armazenado útil chamado sp_spaceused que retornará todo o espaço usado pelo banco de dados. Se fornecido com um nome de tabela, ele retornará o espaço usado por essa tabela. No entanto, os resultados retornados pelo procedimento armazenado não são classificáveis, pois as colunas são valores de caracteres.

O script a seguir irá gerar as informações que estou procurando.

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
fonte
Depois de ver o exposto acima usando o foreach e o SP ia escrever algo assim, feliz por ter rolado a página para baixo e ver que isso me salvou um pouco de tempo.
214 Brad Brad
37
 exec  sp_spaceused N'dbo.MyTable'

Para todas as tabelas, use .. (adicionando os comentários de Paul)

exec sp_MSForEachTable 'exec sp_spaceused [?]'
Royi Namir
fonte
5
Sneaky - você mudou do exec sp_helpdbque não mostra nada sobre tabelas, para o exec sp_spaceusedque mostra - mas apenas para uma tabela de cada vez ... não fornece uma visão geral de quais tabelas você possui, quantas linhas elas possuem e como muito espaço que eles ocupam.
Marc
4
exec sp_MSForEachTable 'exec sp_spaceused [?]'
Paul
27

As consultas acima são boas para encontrar a quantidade de espaço usada pela tabela (índices incluídos), mas se você quiser comparar quanto espaço é usado pelos índices na tabela, use esta consulta:

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
fonte
Por que a soma da coluna Indexsize (KB) de uma tabela específica não concorda com o index_size de sp_spaceused?
Derek
@Derek Corrigido sua resposta adicionando where [i].[is_primary_key] = 0. Agora os tamanhos devem corresponder.
CodeAngry
Obrigado, mas isso também não está funcionando. Eu tenho um banco de dados de teste (muito pequeno), a tabela de interesse possui dois índices - um índice clusterizado primário em uma coluna e um índice não clusterizado em duas das outras colunas. Esta consulta diz que cada um deles está usando 16kB, mas sp_spaceused diz que o uso total do índice é 24kB. Parte da minha confusão é esta: comparando esta consulta com o "UsedSpaceKB" da resposta aceita, não vejo uma diferença real. Mesmas associações, faltando apenas a adição de sys.tables. Estou faltando alguma coisa ou esta consulta está intrinsecamente quebrada?
Derek
Eu tenho grandes bancos de dados. E tamanhos combinam com sp_spaceused. Eu medi GBs, então alguns megas não correspondentes não são muito. Eu não me importo com tamanhos exatos, apenas uma ideia.
CodeAngry
14

Se você precisar calcular exatamente os mesmos números, que estão na página 'table properties - storage' no SSMS, precisará contá-los com o mesmo método usado no SSMS (funciona para o sql server 2005 e superior ... e também funciona corretamente para tabelas com campos LOB - porque apenas contar "páginas_utilizadas" não é suficiente para mostrar o tamanho exato do índice):

;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
fonte
14

Extensão para a resposta @xav que manipulava partições de tabela para obter tamanho em MB e GB. Testado no SQL Server 2008/2012 (comentou uma linha em que 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
fonte
também melhor ordem de classificação.
Pxtl
Essa deve ser a resposta principal.
Baodad 7/10/19
14

Para o Azure, usei isso:

Você deve ter o SSMS v17.x

Eu usei;

insira a descrição da imagem aqui

Com isso, como o usuário Sparrow mencionou :

Abra o seu Databases> e selecione Tabelas .
Em seguida , pressione a tecla F7. Você deve ver o seguinte row count
: insira a descrição da imagem aqui

O SSMS aqui está conectado aos bancos de dados do Azure

Irf
fonte
3
F7 é muito subutilizado.
cskwg
1
Eu não fazia ideia de que isso existia, tenho um pouco de vergonha de mim: p Obrigado!
Lollancf37
Ele tem um problema com tabelas de memória otimizada, (eu apenas testado depois de ver este post :)
Amirreza
11

Usamos o particionamento de tabela e tivemos alguns problemas com as consultas fornecidas acima devido a registros duplicados.

Para aqueles que precisam disso, você pode encontrar abaixo a consulta executada pelo SQL Server 2014 ao gerar o relatório "Uso do disco por tabela". Suponho que ele também funcione com versões anteriores do SQL Server.

Ele funciona como um encanto.

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
fonte
Obrigado por um script que corresponde à maneira como o SSMS faz isso e lida corretamente com partições.
28518 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
Marca
fonte
8

Uma pequena alteração na resposta de Mar_c , já que voltei a esta página com tanta frequência, ordenada pela maioria das linhas primeiro:

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
fonte
5

Isso fornecerá os tamanhos e as contagens de registros para cada tabela.

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
fonte
2
Se você código postal, amostras XML ou dados, POR FAVOR destacar as linhas no editor de texto e clique no botão "código de amostras" ( { }) na barra de ferramentas do editor de bem formato e sintaxe destacá-lo!
Marc
4

Para obter todo o tamanho da tabela em um banco de dados, você pode usar esta consulta:

Exec sys.sp_MSforeachtable ' sp_spaceused "?" '

E você pode alterá-lo para inserir todos os resultados na tabela temporária e depois selecionar na tabela temporária.

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

Em um prompt de comando usando o OSQL :

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

Aqui está uma maneira de obter todos os tamanhos de tabelas rapidamente, com as seguintes etapas:

  1. Escreva os comandos T-SQL fornecidos para listar todas as tabelas do banco de dados:

    select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
  2. Agora copie a lista de tabelas do banco de dados e copie-a para uma nova janela do analisador de consultas

    exec sp_spaceused table1
    exec sp_spaceused table2
    exec sp_spaceused table3
    exec sp_spaceused table4
    exec sp_spaceused table5
  3. No analisador de consultas SQL , selecione na opção da barra de ferramentas superior Resultados para o arquivo ( Ctrl+ Shift+ F).

  4. Agora, finalmente, pressione o botão Executar , vermelho, marcado na barra de ferramentas acima .

  5. O tamanho do banco de dados de todas as tabelas agora está armazenado em um arquivo no seu computador.

    Digite a descrição da imagem aqui

Anjan Kant
fonte
2

Adicionei mais algumas colunas sobre a resposta 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
fonte
1

Minha postagem é relevante apenas para o SQL Server 2000 e foi testada para funcionar em meu ambiente.

Esse código acessa todos os bancos de dados possíveis de uma única instância , não apenas um único banco de dados.

Uso duas tabelas temporárias para ajudar a coletar os dados apropriados e depois despejar os resultados em uma tabela 'Ao vivo'.

Os dados retornados são: DatabaseName, DatabaseTableName, Rows (na tabela), dados (tamanho da tabela em KB que parece), dados de entrada (acho útil para saber quando eu executei o script pela última vez).

A queda desse código é o campo 'data' não é armazenado como um int (os caracteres 'KB' são mantidos nesse campo) e isso seria útil (mas não totalmente necessário) para classificação.

Espero que este código ajude alguém por aí e economize algum tempo!

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] 

Caso você precise saber, a tabela rsp_DatabaseTableSizes foi criada por meio de:

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

GO
Andrew
fonte
1

Como uma extensão simples da resposta de marc_s (a que foi aceita), isso é ajustado para retornar a contagem de colunas e permitir a filtragem:

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
fonte
Depois de ingressar na tabela Colunas, você não terá mais o espaço de tabela correto. A aplicação externa será a correção.
Dreamca4er 31/10/19
0

Usando a resposta @Mark acima, adicionou @ updateusage = 'true' para forçar as estatísticas de tamanho mais recentes ( 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
fonte
0

Aqui está um exemplo de consulta para obter tabelas maiores que 1 GB ordenadas por tamanho decrescente.

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
fonte