Consulta para listar o número de registros em cada tabela em um banco de dados


197

Como listar a contagem de linhas de cada tabela no banco de dados. Algum equivalente de

select count(*) from table1
select count(*) from table2
...
select count(*) from tableN

Vou postar uma solução, mas outras abordagens são bem-vindas

Respostas:


312

Se você estiver usando o SQL Server 2005 e superior, também poderá usar o seguinte:

SELECT 
    t.NAME AS TableName,
    i.name as indexName,
    p.[Rows],
    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.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
WHERE 
    t.NAME NOT LIKE 'dt%' AND
    i.OBJECT_ID > 255 AND   
    i.index_id <= 1
GROUP BY 
    t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY 
    object_name(i.object_id) 

Na minha opinião, é mais fácil de manusear do que a sp_msforeachtablesaída.


1
Alguma idéia de por que ele está filtrando tabelas com um nome começando com "dt"? Eu já vi esse script em toda a rede, mas nenhuma explicação sobre esse critério. Estamos todos sendo trollados?
Skaue

6
@Skaue: se você instalar a funcionalidade "Diagrama do Banco de Dados" em um banco de dados seu, terá algumas tabelas como dtPropertiesesta; como essas são tabelas de "sistema", não quero informar sobre elas.
Marc # 15/13

1
Possibilidade de prefixar o nome da tabela com o nome do esquema neste script?
Gh0st

Por algum motivo, essa consulta não está retornando todas as tabelas. Eu tenho 382 tabelas em um banco de dados. Mas essa consulta está retornando apenas 270 linhas (informações da tabela). Depois de remover a condição where, estou recebendo 302 linhas. É devido ao fato de que algumas das informações da tabela estão ausentes de uma das tabelas SYS e, portanto, as junções as estão omitindo. O banco de dados não contém nenhuma tabela do sistema.
Ankesh Kushwah

Isso está funcionando. você pode modificá-lo para comparar dois bancos de dados.
Sanjeewa

107

Um trecho que encontrei em http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 que me ajudou:

select t.name TableName, i.rows Records
from sysobjects t, sysindexes i
where t.xtype = 'U' and i.id = t.id and i.indid in (0,1)
order by TableName;

5
Eu gosto dessa solução, apesar de usar a JOINsintaxe #from sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
Shnugo 27/10

Também prefiro usar as instruções JOIN, mas publiquei o snippet de código como o encontrei. :)
Erik Anderson

32

Para obter essas informações no SQL Management Studio, clique com o botão direito do mouse no banco de dados e selecione Relatórios -> Relatórios Padrão -> Uso do Disco por Tabela.


6
Abordagem subestimada, isso gera rapidamente um relatório classificável mostrando # linhas e tamanho dos dados.
tbone

8
SELECT 
    T.NAME AS 'TABLE NAME',
    P.[ROWS] AS 'NO OF ROWS'
FROM SYS.TABLES T 
INNER JOIN  SYS.PARTITIONS P ON T.OBJECT_ID=P.OBJECT_ID;

3
Esta consulta retornará um resultado de linhas para cada índice em todas as tabelas. Adicione WHERE P.INDEX_ID IN (0,1) para limitar o resultado do retorno definido para heaps ou índices agrupados somente onde apropriado.
Rasmus Remmer Bielidt

6

Como visto aqui, isso retornará contagens corretas, onde os métodos que usam as tabelas de metadados retornarão apenas estimativas.

    CREATE PROCEDURE ListTableRowCounts 
    AS 
    BEGIN 
        SET NOCOUNT ON 

        CREATE TABLE #TableCounts
        ( 
            TableName VARCHAR(500), 
            CountOf INT 
        ) 

        INSERT #TableCounts
            EXEC sp_msForEachTable 
                'SELECT PARSENAME(''?'', 1), 
                COUNT(*) FROM ? WITH (NOLOCK)' 

        SELECT TableName , CountOf 
            FROM #TableCounts
            ORDER BY TableName 

        DROP TABLE #TableCounts
    END
    GO

Portanto, parece um comprometimento do uso de stor proc indocumentado sp_msForEachTable vs o uso de tabelas de sistema com informações às vezes não muito atualizadas. +1 e obrigado pelo link
kristof

3
sp_MSForEachTable 'DECLARE @t AS VARCHAR(MAX); 
SELECT @t = CAST(COUNT(1) as VARCHAR(MAX)) 
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT @t'

Resultado:

insira a descrição da imagem aqui


Eu precisava de algo para o Sql Server 2000. Isso funcionou. Obrigado!
Alrekr

3

Felizmente, o SQL Server Management Studio fornece uma dica sobre como fazer isso. Faça isso,

  1. inicie um rastreamento do SQL Server e abra a atividade que você está realizando (filtre por seu ID de logon se não estiver sozinho e defina o Nome do aplicativo como Microsoft SQL Server Management Studio), pause o rastreamento e descarte os resultados que você registrou até agora;
  2. Em seguida, clique com o botão direito do mouse em uma tabela e selecione a propriedade no menu pop-up;
  3. inicie o rastreamento novamente;
  4. Agora, no SQL Server Management studio, selecione o item de propriedade de armazenamento à esquerda;

Interrompa o rastreamento e veja o que o TSQL é gerado pela microsoft.

Provavelmente, na última consulta, você verá uma instrução começando com exec sp_executesql N'SELECT

ao copiar o código executado no visual studio, você notará que esse código gera todos os dados que os engenheiros da microsoft usaram para preencher a janela de propriedades.

quando você faz modificações moderadas nessa consulta, chega a algo assim:

SELECT
SCHEMA_NAME(tbl.schema_id)+'.'+tbl.name as [table], --> something I added
p.partition_number AS [PartitionNumber],
prv.value AS [RightBoundaryValue],
 fg.name AS [FileGroupName],
CAST(pf.boundary_value_on_right AS int) AS [RangeType],
CAST(p.rows AS float) AS [RowCount],
p.data_compression AS [DataCompression]
FROM sys.tables AS tbl
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and idx.index_id < 2
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) AND p.index_id=idx.index_id
LEFT OUTER JOIN sys.destination_data_spaces AS dds ON dds.partition_scheme_id = idx.data_space_id and dds.destination_id = p.partition_number
LEFT OUTER JOIN sys.partition_schemes AS ps ON ps.data_space_id = idx.data_space_id
LEFT OUTER JOIN sys.partition_range_values AS prv ON prv.boundary_id = p.partition_number and prv.function_id = ps.function_id
LEFT OUTER JOIN sys.filegroups AS fg ON fg.data_space_id = dds.data_space_id or fg.data_space_id = idx.data_space_id
LEFT OUTER JOIN sys.partition_functions AS pf ON  pf.function_id = prv.function_id

Agora, a consulta não está perfeita e você pode atualizá-la para atender a outras perguntas que você possa ter. O ponto é que você pode usar o conhecimento da Microsoft para obter a maioria das perguntas que você possui, executando os dados de seu interesse e rastreando o TSQL gerado usando o criador de perfil.

Eu meio que gosto de pensar que os engenheiros da MS sabem como o servidor SQL funciona e, ele gerará TSQL que funciona em todos os itens com os quais você pode trabalhar usando a versão no SSMS que você está usando, por isso é muito bom em uma grande variedade de versões pré-existentes, atuais e futuro.

E lembre-se, não apenas copie, tente entendê-lo, senão você pode acabar com a solução errada.

Walter


2

Essa abordagem usa a concatenação de strings para produzir uma declaração com todas as tabelas e suas contagens dinamicamente, como nos exemplos dados na pergunta original:

          SELECT COUNT(*) AS Count,'[dbo].[tbl1]' AS TableName FROM [dbo].[tbl1]
UNION ALL SELECT COUNT(*) AS Count,'[dbo].[tbl2]' AS TableName FROM [dbo].[tbl2]
UNION ALL SELECT...

Finalmente, isso é executado com EXEC:

DECLARE @cmd VARCHAR(MAX)=STUFF(
                    (
                        SELECT 'UNION ALL SELECT COUNT(*) AS Count,''' 
                              + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME) 
                              + ''' AS TableName FROM ' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME)
                        FROM INFORMATION_SCHEMA.TABLES AS t
                        WHERE TABLE_TYPE='BASE TABLE'
                        FOR XML PATH('')
                    ),1,10,'');
EXEC(@cmd);

Note-se que esta solução inclui o nome do esquema (que pode ser útil)
gordon613


1

A primeira coisa que veio à mente foi usar sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

que não lista os nomes das tabelas, portanto, pode ser estendido para

exec sp_msforeachtable 'select parsename(''?'', 1),  count(*) from ?'

O problema aqui é que, se o banco de dados tiver mais de 100 tabelas, você receberá a seguinte mensagem de erro:

A consulta excedeu o número máximo de conjuntos de resultados que podem ser exibidos na grade de resultados. Somente os 100 primeiros conjuntos de resultados são exibidos na grade.

Então acabei usando a variável de tabela para armazenar os resultados

declare @stats table (n sysname, c int)
insert into @stats
    exec sp_msforeachtable 'select parsename(''?'', 1),  count(*) from ?'
select 
    * 
from @stats
order by c desc

1

A resposta aceita não funcionou para mim no Azure SQL, aqui está uma que funcionou, é super rápida e fez exatamente o que eu queria:

select t.name, s.row_count
from sys.tables t
join sys.dm_db_partition_stats s
  ON t.object_id = s.object_id
    and t.type_desc = 'USER_TABLE'
    and t.name not like '%dss%'
    and s.index_id = 1
order by s.row_count desc

1

Esse script sql fornece o esquema, o nome da tabela e a contagem de linhas de cada tabela em um banco de dados selecionado:

SELECT SCHEMA_NAME(schema_id) AS [SchemaName],
[Tables].name AS [TableName],
SUM([Partitions].[rows]) AS [TotalRowCount]
FROM sys.tables AS [Tables]
JOIN sys.partitions AS [Partitions]
ON [Tables].[object_id] = [Partitions].[object_id]
AND [Partitions].index_id IN ( 0, 1 )
-- WHERE [Tables].name = N'name of the table'
GROUP BY SCHEMA_NAME(schema_id), [Tables].name
order by [TotalRowCount] desc

Ref: https://blog.sqlauthority.com/2017/05/24/sql-server-find-row-count-every-table-database-efficiently/

Outra maneira de fazer isso:

SELECT  o.NAME TABLENAME,
  i.rowcnt 
FROM sysindexes AS i
  INNER JOIN sysobjects AS o ON i.id = o.id 
WHERE i.indid < 2  AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0
ORDER BY i.rowcnt desc

0

Eu acho que a maneira mais curta, rápida e simples seria:

SELECT
    object_name(object_id) AS [Table],
    SUM(row_count) AS [Count]
FROM
    sys.dm_db_partition_stats
WHERE
    --object_schema_name(object_id) = 'dbo' AND 
    index_id < 2
GROUP BY
    object_id

0

Você pode tentar o seguinte:

SELECT  OBJECT_SCHEMA_NAME(ps.object_Id) AS [schemaname],
        OBJECT_NAME(ps.object_id) AS [tablename],
        row_count AS [rows]
FROM sys.dm_db_partition_stats ps
WHERE OBJECT_SCHEMA_NAME(ps.object_Id) <> 'sys' AND ps.index_id < 2
ORDER BY 
        OBJECT_SCHEMA_NAME(ps.object_Id),
        OBJECT_NAME(ps.object_id)

0
USE DatabaseName
CREATE TABLE #counts
(
    table_name varchar(255),
    row_count int
)

EXEC sp_MSForEachTable @command1='INSERT #counts (table_name, row_count) SELECT ''?'', COUNT(*) FROM ?'
SELECT table_name, row_count FROM #counts ORDER BY table_name, row_count DESC
DROP TABLE #counts

0

Nesta pergunta: /dba/114958/list-all-tables-from-all-user-databases/230411#230411

Adicionei contagem de registros à resposta fornecida por @Aaron Bertrand que lista todos os bancos de dados e todas as tabelas.

DECLARE @src NVARCHAR(MAX), @sql NVARCHAR(MAX);

SELECT @sql = N'', @src = N' UNION ALL 
SELECT ''$d'' as ''database'', 
    s.name COLLATE SQL_Latin1_General_CP1_CI_AI as ''schema'',
    t.name COLLATE SQL_Latin1_General_CP1_CI_AI as ''table'' ,
    ind.rows as record_count
  FROM [$d].sys.schemas AS s
  INNER JOIN [$d].sys.tables AS t ON s.[schema_id] = t.[schema_id]
  INNER JOIN [$d].sys.sysindexes AS ind ON t.[object_id] = ind.[id]
  where ind.indid < 2';

SELECT @sql = @sql + REPLACE(@src, '$d', name)
  FROM sys.databases
  WHERE database_id > 4
    AND [state] = 0
    AND HAS_DBACCESS(name) = 1;

SET @sql = STUFF(@sql, 1, 10, CHAR(13) + CHAR(10));

PRINT @sql;
--EXEC sys.sp_executesql @sql;

0

Você pode copiar, colar e executar esse trecho de código para obter todas as contagens de registros em uma tabela. Nota: O código é comentado com instruções

create procedure RowCountsPro
as
begin
--drop the table if exist on each exicution
IF OBJECT_ID (N'dbo.RowCounts', N'U') IS NOT NULL 
DROP TABLE dbo.RowCounts;
-- creating new table
CREATE TABLE RowCounts 
( [TableName]            VARCHAR(150)
, [RowCount]               INT
, [Reserved]                 NVARCHAR(50)
, [Data]                        NVARCHAR(50)
, [Index_Size]               NVARCHAR(50)
, [UnUsed]                   NVARCHAR(50))
--inserting all records
INSERT INTO RowCounts([TableName], [RowCount],[Reserved],[Data],[Index_Size],[UnUsed])
--  "sp_MSforeachtable" System Procedure, 'sp_spaceused "?"' param to get records and resources used
EXEC sp_MSforeachtable 'sp_spaceused "?"' 
-- selecting data and returning a table of data
SELECT [TableName], [RowCount],[Reserved],[Data],[Index_Size],[UnUsed]
FROM RowCounts
ORDER BY [TableName]
end

Eu testei esse código e funciona bem no SQL Server 2014.


0

Quero compartilhar o que está funcionando para mim

SELECT
      QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) AS [TableName]
      , SUM(sdmvPTNS.row_count) AS [RowCount]
FROM
      sys.objects AS sOBJ
      INNER JOIN sys.dm_db_partition_stats AS sdmvPTNS
            ON sOBJ.object_id = sdmvPTNS.object_id
WHERE 
      sOBJ.type = 'U'
      AND sOBJ.is_ms_shipped = 0x0
      AND sdmvPTNS.index_id < 2
GROUP BY
      sOBJ.schema_id
      , sOBJ.name
ORDER BY [TableName]
GO

O banco de dados está hospedado no Azure e o resultado final é: insira a descrição da imagem aqui

Crédito: https://www.mssqltips.com/sqlservertip/2537/sql-server-row-count-for-all-tables-in-a-database/


-1

Se você usa MySQL> 4.x, pode usar isto:

select TABLE_NAME, TABLE_ROWS from information_schema.TABLES where TABLE_SCHEMA="test";

Lembre-se de que, para alguns mecanismos de armazenamento, TABLE_ROWS é uma aproximação.


6
ele mencionou "sql-server" em seu posto (como um tag), que é o Microsoft SQL Server
marc_s

-1
select T.object_id, T.name, I.indid, I.rows 
  from Sys.tables T 
  left join Sys.sysindexes I 
    on (I.id = T.object_id and (indid =1 or indid =0 ))
 where T.type='U'

Aqui indid=1significa um índice CLUSTERED e indid=0é um HEAP


4
Olá e bem-vindo ao Stack Overflow. Esta resposta é idêntica a uma que já tem um ano ... não havia necessidade de publicá-la novamente.
22414 Ben
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.