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


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.