Obtendo a Quantidade de Registros em Todas as Tabelas de um Banco de Dados
Uma forma de descobrir quantos registros existem em cada tabela do banco é percorrer a lista de tabelas do banco e rodar um COUNT(*) em cada uma delas. O script abaixo faz isso usando um cursor, percorrendo a information_schema.tables e executando uma contagem para cada tabela encontrada.
Se você está procurando uma forma rápida de identificar apenas as maiores tabelas do banco, sem contar linha por linha, veja o post sobre identificando as maiores tabelas do seu banco, que resolve isso direto pelas views de sistema, sem precisar rodar
COUNT(*)em cada tabela.
O script com cursor
DECLARE @NomeDaTabela VARCHAR(128);
DECLARE meu_cursor CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';
OPEN meu_cursor;
FETCH NEXT FROM meu_cursor INTO @NomeDaTabela;
WHILE @@FETCH_STATUS = 0
BEGIN
EXECUTE (
'SELECT ''' + @NomeDaTabela + ''' AS Tabela, COUNT(*) AS [Total de Registros] FROM ' + QUOTENAME(@NomeDaTabela)
);
FETCH NEXT FROM meu_cursor INTO @NomeDaTabela;
END;
CLOSE meu_cursor;
DEALLOCATE meu_cursor;
Repare no uso de QUOTENAME(@NomeDaTabela) no FROM do SQL dinâmico: isso protege o comando contra nomes de tabela com espaços, caracteres especiais ou que coincidam com palavras reservadas do SQL Server, cercando o nome com colchetes automaticamente.
Um cuidado com bancos que têm mais de um schema
O script busca apenas pelo nome da tabela (TABLE_NAME), sem considerar o schema (TABLE_SCHEMA). Se o seu banco tiver tabelas com o mesmo nome em schemas diferentes (por exemplo, vendas.Pedidos e arquivo.Pedidos), o script original pode contar a tabela errada ou falhar. Para evitar isso, inclua o schema também:
DECLARE @NomeDaTabela VARCHAR(128);
DECLARE @Schema VARCHAR(128);
DECLARE meu_cursor CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';
OPEN meu_cursor;
FETCH NEXT FROM meu_cursor INTO @Schema, @NomeDaTabela;
WHILE @@FETCH_STATUS = 0
BEGIN
EXECUTE (
'SELECT ''' + @Schema + '.' + @NomeDaTabela + ''' AS Tabela, COUNT(*) AS [Total de Registros] FROM '
+ QUOTENAME(@Schema) + '.' + QUOTENAME(@NomeDaTabela)
);
FETCH NEXT FROM meu_cursor INTO @Schema, @NomeDaTabela;
END;
CLOSE meu_cursor;
DEALLOCATE meu_cursor;
Por que essa abordagem pode ser lenta
Esse script faz um COUNT(*) de verdade, tabela por tabela, o que garante uma contagem exata no momento da execução. O custo é que, em bancos com tabelas muito grandes, cada COUNT(*) precisa ler a tabela inteira (ou o índice mais compacto disponível), o que pode deixar o script lento em bancos grandes com muitas tabelas.
Se o objetivo é apenas ter uma ideia do tamanho das tabelas, sem precisar de uma contagem exata em tempo real, o SQL Server já mantém essa informação pronta nas views de sistema sys.partitions, sem precisar percorrer tabela por tabela. Veja o post sobre identificando as maiores tabelas do seu banco para essa alternativa, muito mais rápida em bases grandes.
Alternativa sem cursor: um único resultado, ao invés de vários
Um efeito colateral do script com cursor é que cada EXECUTE gera um resultado separado, um por tabela. Se você preferir um único resultado consolidado, é possível montar dinamicamente uma consulta com UNION ALL, usando STRING_AGG (disponível desde o SQL Server 2017) para juntar tudo em um só comando:
DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = STRING_AGG(
'SELECT ''' + TABLE_SCHEMA + '.' + TABLE_NAME + ''' AS Tabela, COUNT(*) AS [Total de Registros] FROM '
+ QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME),
' UNION ALL '
)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';
EXEC (@SQL);
Essa versão continua fazendo um COUNT(*) por tabela (o custo de leitura é o mesmo), mas devolve tudo em um único resultado, mais fácil de visualizar e exportar.
Conclusão
O script com cursor é uma forma direta de obter a contagem exata de registros de todas as tabelas do banco, e vale reforçar o QUOTENAME para lidar com nomes de tabela fora do padrão. Para bancos muito grandes, onde rodar COUNT(*) em cada tabela fica caro, considere a alternativa via sys.partitions, que entrega uma estimativa quase instantânea sem precisar ler os dados.