Consulta para enumerar el número de registros en cada tabla en una base de datos

198

Cómo enumerar el recuento de filas de cada tabla en la base de datos. Algún equivalente de

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

Publicaré una solución, pero otros enfoques son bienvenidos

kristof
fuente

Respuestas:

313

Si usa SQL Server 2005 y versiones posteriores, también puede usar esto:

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) 

En mi opinión, es más fácil de manejar que la sp_msforeachtablesalida.

marc_s
fuente
1
¿Alguna idea de por qué está filtrando tablas con un nombre que comienza con "dt"? He visto este script en toda la red, pero no hay explicación sobre ese criterio. ¿Estamos todos siendo trolleados?
Skaue
66
@Skaue: si instala la funcionalidad "Diagrama de base de datos" en una base de datos suya, tendrá algunas tablas como, dtPropertiesetc. Como esas son tablas de "sistema", no quiero informar sobre ellas.
marc_s
1
¿Posibilidad de prefijar el nombre de la tabla con el nombre del esquema en este script?
gh0st
Por alguna razón, esta consulta no devuelve todas las tablas. Tengo 382 tablas en una base de datos. Pero esta consulta solo devuelve 270 filas (información de la tabla). Después de eliminar la condición where, obtengo 302 filas. ¿Se debe al hecho de que falta parte de la información de las tablas en una de las tablas SYS, por lo que las uniones las omiten? La base de datos no contiene ninguna tabla del sistema.
Ankesh Kushwah
Esto esta funcionando. ¿Puedes modificarlo para comparar dos bases de datos?
sanjeewa
107

Un fragmento que encontré en http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 que me ayudó:

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;
Erik Anderson
fuente
55
Me gusta esta solución, aunque usaría la JOINsintaxisfrom sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
Shnugo
Prefiero usar sentencias JOIN también, pero publiqué el fragmento de código tal como lo encontré. :)
Erik Anderson
32

Para obtener esa información en SQL Management Studio, haga clic derecho en la base de datos, luego seleccione Informes -> Informes estándar -> Uso de disco por tabla.

petra
fuente
66
Enfoque subestimado, esto genera rápidamente un informe ordenable que muestra # filas y el tamaño de los datos.
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;
ANG
fuente
3
Esta consulta devolverá un resultado de filas para cada índice en cada tabla. Agregue un WHIND P.INDEX_ID IN (0,1) para limitar el conjunto de resultados devueltos a montones o índices agrupados solo cuando sea apropiado.
Rasmus Remmer Bielidt
6

Como se ve aquí, esto devolverá conteos correctos, donde los métodos que usan las tablas de metadatos solo devolverán estimaciones.

    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
KM.
fuente
Por lo tanto, parece un compromiso de usar stor proc sp_msForEachTable indocumentado en lugar de usar tablas del sistema con información a veces no más actualizada. +1 y gracias por el enlace
kristof
3
sp_MSForEachTable 'DECLARE @t AS VARCHAR(MAX); 
SELECT @t = CAST(COUNT(1) as VARCHAR(MAX)) 
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT @t'

Salida:

ingrese la descripción de la imagen aquí

Rikin Patel
fuente
Necesitaba algo para SQL Server 2000. Esto funcionó. ¡Gracias!
Alrek
3

Afortunadamente, el estudio de administración de SQL Server le da una pista sobre cómo hacer esto. Hacer esto,

  1. inicie un rastreo de SQL Server y abra la actividad que está realizando (filtre por su ID de inicio de sesión si no está solo y configure el Nombre de la aplicación en Microsoft SQL Server Management Studio), pause el rastreo y descarte los resultados que haya registrado hasta ahora;
  2. Luego, haga clic derecho en una tabla y seleccione la propiedad del menú emergente;
  3. comenzar de nuevo la traza;
  4. Ahora en el estudio de SQL Server Management, seleccione el elemento de propiedad de almacenamiento a la izquierda;

Pause el seguimiento y eche un vistazo a lo que TSQL genera Microsoft.

En la última consulta probablemente verá una declaración que comienza con exec sp_executesql N'SELECT

Cuando copie el código ejecutado en Visual Studio, notará que este código genera todos los datos que los ingenieros de Microsoft utilizaron para llenar la ventana de propiedades.

cuando realice modificaciones moderadas a esa consulta, obtendrá algo como esto:

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

Ahora la consulta no es perfecta y puede actualizarla para cumplir con otras preguntas que pueda tener, el punto es que puede usar el conocimiento de microsoft para llegar a la mayoría de las preguntas que tiene ejecutando los datos que le interesan y rastrear el TSQL generado usando profiler.

Me gusta pensar que los ingenieros de MS saben cómo funciona el servidor SQL y generará TSQL que funciona en todos los elementos con los que puede trabajar utilizando la versión en SSMS que está utilizando, por lo que es bastante bueno en una gran variedad de versiones prerviouse, actual y futuro.

Y recuerde, no solo copie, intente comprenderlo también, de lo contrario podría terminar con la solución incorrecta.

Walter

Walter Verhoeven
fuente
2

Este enfoque utiliza la concatenación de cadenas para producir una declaración con todas las tablas y sus recuentos dinámicamente, como los ejemplos dados en la pregunta 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 esto se ejecuta con 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);
Shnugo
fuente
tenga en cuenta que esta solución incluye el nombre del esquema (que puede ser útil)
gordon613
1

Lo primero que se me ocurrió fue usar sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

sin embargo, eso no enumera los nombres de las tablas, por lo que se puede extender a

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

El problema aquí es que si la base de datos tiene más de 100 tablas, recibirá el siguiente mensaje de error:

La consulta ha excedido el número máximo de conjuntos de resultados que se pueden mostrar en la cuadrícula de resultados. Solo los primeros 100 conjuntos de resultados se muestran en la cuadrícula.

Así que terminé usando la variable de tabla para almacenar los 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
kristof
fuente
1

La respuesta aceptada no funcionó para mí en Azure SQL, aquí hay una que sí, es súper rápida e hizo exactamente lo que quería:

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
UnionP
fuente
1

Este script sql proporciona el esquema, el nombre de la tabla y el recuento de filas de cada tabla en una base de datos seleccionada:

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/

Otra forma de hacer esto:

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
rchacko
fuente
0

Creo que la forma más corta, rápida y sencilla sería:

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
sotn
fuente
0

Podrías probar esto:

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)
Steve Ford
fuente
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
foluis
fuente
0

De esta pregunta: /dba/114958/list-all-tables-from-all-user-databases/230411#230411

Agregué un recuento de registros a la respuesta proporcionada por @Aaron Bertrand que enumera todas las bases de datos y todas las tablas.

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;
Jeremy F.
fuente
0

Puede copiar, pegar y ejecutar este código para obtener todos los recuentos de registros de la tabla en una tabla. Nota: el código se comenta con instrucciones

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

He probado este código y funciona bien en SQL Server 2014.

Mujtaba
fuente
0

Quiero compartir lo que me funciona.

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

La base de datos está alojada en Azure y el resultado final es: ingrese la descripción de la imagen aquí

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

d.danailov
fuente
-1

Si usa MySQL> 4.x puede usar esto:

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

Tenga en cuenta que para algunos motores de almacenamiento, TABLE_ROWS es una aproximación.

David Poblador i Garcia
fuente
66
mencionó "sql-server" en su puesto (como una etiqueta) que es 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'

Aquí indid=1significa un índice agrupado y indid=0es un HEAP

Jyoti prashad chaulkara
fuente
44
Hola y bienvenido a Stack Overflow. Esta respuesta es idéntica a una que ya tiene un año ... no hubo necesidad de publicarla nuevamente.
Ben