Запрос для перечисления количества записей в каждой таблице в базе данных


206

Как перечислить количество строк каждой таблицы в базе данных. Какой-то эквивалент

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

Я опубликую решение, но приветствуются другие подходы

Ответы:


324

Если вы используете SQL Server 2005 и выше, вы также можете использовать это:

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) 

На мой взгляд, это проще в обращении, чем на sp_msforeachtableвыходе.


1
Есть идеи, почему он фильтрует таблицы с именем, начинающимся с «dt»? Я видел этот сценарий по всей сети, но никаких объяснений по этим критериям. Нас всех троллируют?
— Скауэ

6
@Skaue: если вы установите функциональность «Диаграмма базы данных» в свою базу данных, то у вас будет несколько таблиц dtPropertiesи т. Д . ; поскольку это «системные» таблицы, я не хочу по ним сообщать.
— marc_s

1
Возможность префикса имени таблицы с именем схемы в этом скрипте?
— gh0st 03

По какой-то причине этот запрос не возвращает все таблицы. У меня в базе 382 таблицы. Но этот запрос возвращает только 270 строк (табличная информация). После удаления условия where я получаю 302 строки. Это связано с тем, что некоторая информация о таблицах отсутствует в одной из таблиц SYS, поэтому соединения пропускают их. База данных не содержит системных таблиц.
— Ankesh Kushwah

Это работает. Можете ли вы изменить его для сравнения двух баз данных.
— sanjeewa

110

Фрагмент, который я нашел на http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=21021 , мне помог:

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
Мне нравится это решение, хотя я бы использовал JOINсинтаксисfrom sysobjects t inner join sysindexes i on i.id = t.id and i.indid in (0,1) where t.xtype = 'U'
— Shnugo

Я тоже предпочитаю использовать операторы JOIN, но разместил фрагмент кода таким, каким я его нашел. :)
— Эрик Андерсон

35

Чтобы получить эту информацию в SQL Management Studio, щелкните правой кнопкой мыши базу данных, затем выберите «Отчеты» -> «Стандартные отчеты» -> «Использование диска по таблице».


7
Недооцененный подход, при этом быстро создается сортируемый отчет, показывающий # строк и размер данных.
— 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
Этот запрос вернет результат строк для каждого индекса в каждой таблице. Добавьте WHERE P.INDEX_ID IN (0,1), чтобы ограничить набор возвращаемых результатов кучей или кластеризованными индексами только там, где это необходимо.
— Расмус Реммер Билидт 01

6

Как видно здесь, это вернет правильные подсчеты, тогда как методы, использующие таблицы метаданных, будут возвращать только оценки.

    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

Это звучит как компромисс между использованием недокументированного stor proc sp_msForEachTable и использованием системных таблиц с иногда не самой последней информацией. +1 и спасибо за ссылку
— kristof

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

Выход:

введите описание изображения здесь


Мне нужно что-то для Sql Server 2000. Это сработало. Благодарность!
— Alrekr

3

К счастью, студия управления SQL Server дает вам подсказку, как это сделать. Сделай это,

  1. запустите трассировку SQL Server и откройте выполняемое действие (отфильтруйте по идентификатору входа, если вы не одиноки, и задайте имя приложения Microsoft SQL Server Management Studio), приостановите трассировку и отмените все результаты, записанные до сих пор;
  2. Затем щелкните таблицу правой кнопкой мыши и выберите свойство во всплывающем меню;
  3. снова запустить трассировку;
  4. Теперь в SQL Server Management Studio выберите слева элемент свойства хранилища;

Приостановите трассировку и посмотрите, какой TSQL генерирует Microsoft.

В возможно последнем запросе вы увидите оператор, начинающийся с exec sp_executesql N'SELECT

когда вы копируете выполненный код в Visual Studio, вы заметите, что этот код генерирует все данные, которые инженеры Microsoft использовали для заполнения окна свойств.

когда вы внесете умеренные изменения в этот запрос, вы получите что-то вроде этого:

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

Теперь запрос не идеален, и вы можете обновить его, чтобы ответить на другие вопросы, которые могут у вас возникнуть. Дело в том, что вы можете использовать знания Microsoft, чтобы получить ответы на большинство вопросов, которые у вас есть, выполнив интересующие вас данные и отслеживая TSQL, созданный с помощью профилировщика.

Мне нравится думать, что инженеры MS знают, как работает SQL-сервер, и он будет генерировать TSQL, который работает со всеми элементами, с которыми вы можете работать, используя версию SSMS, которую вы используете, так что это неплохо для большого количества предварительных, текущих и будущее.

И помните, не просто копируйте, пытайтесь понять это, иначе вы можете прийти к неправильному решению.

Уолтер


2

Этот подход использует конкатенацию строк для динамического создания оператора со всеми таблицами и их счетчиками, как в примерах, приведенных в исходном вопросе:

          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...

Наконец, это выполняется с помощью 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);

обратите внимание, что это решение включает имя схемы (что может быть полезно)
— gordon613


1

Первое, что пришло в голову, это использовать sp_msForEachTable

exec sp_msforeachtable 'select count(*) from ?'

который не перечисляет имена таблиц, поэтому его можно расширить до

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

Проблема здесь в том, что если в базе данных более 100 таблиц, вы получите следующее сообщение об ошибке:

Запрос превысил максимальное количество наборов результатов, которые могут отображаться в таблице результатов. В сетке отображаются только первые 100 наборов результатов.

В итоге я использовал табличную переменную для хранения результатов

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

Принятый ответ не сработал для меня в Azure SQL, вот тот, который сработал , он очень быстрый и сделал именно то, что я хотел:

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

Этот sql-скрипт дает схему, имя таблицы и количество строк каждой таблицы в выбранной базе данных:

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

Ссылка: https://blog.sqlauthority.com/2017/05/24/sql-server-find-row-count-every-table-database-efficiently/

Другой способ сделать это:

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

1

Я хочу поделиться тем, что у меня работает

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

База данных размещена в Azure, и конечный результат: введите описание изображения здесь

Кредит: https://www.mssqltips.com/sqlservertip/2537/sql-server-row-count-for-all-tables-in-a-database/


0

Я думаю, что самый короткий, быстрый и простой способ:

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

Вы можете попробовать это:

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

Из этого вопроса: /dba/114958/list-all-tables-from-all-user-databases/230411#230411

Я добавил количество записей к ответу @Aaron Bertrand, в котором перечислены все базы данных и все таблицы.

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

Вы можете скопировать, вставить и выполнить этот фрагмент кода, чтобы получить все счетчики записей в таблице. Примечание. Код снабжен комментариями.

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

Я протестировал этот код, и он отлично работает на SQL Server 2014.



-1

Если вы используете MySQL> 4.x, вы можете использовать это:

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

Имейте в виду, что для некоторых механизмов хранения TABLE_ROWS является приблизительным значением.


6
он упомянул "sql-server" в своем сообщении (как тег), которым является 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'

Здесь indid=1означает индекс кластерного и indid=0является пирамидой


4
Привет и добро пожаловать в Stack Overflow. Этот ответ идентичен тому, которому уже исполнился год ... не было необходимости публиковать его снова.
— Бен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.