Click here to Skip to main content
14,325,129 members

How to Count All Tables, Rows, and Rows Per Table

Rate this:
4.60 (11 votes)
Please Sign up or sign in to vote.
4.60 (11 votes)
22 Nov 2015CPOL
This code snippet shows how to count all the tables and rows in a SQL Server database


I do a lot of database administration work for my customers, and quite often I receive requests like this:


How big is our database today? How big was it yesterday? Last month? Last year?

When they ask this sort of question, non-technical people don't want to know the gigabyte size of the SQL Server master data file or the transaction log file. Those metrics don't mean anything to them. Instead, they want to know how many tables are in the database, how many rows are in the database (across all tables), and how many rows are in each table.

I created a simple script to calculate these metrics. (An application could be built to store a history of database size metrics, which would then be useful for charting and predicting database growth. I haven't got to that quite yet...)

This script has been useful in my own DevOps work too, especially when I'm looking at someone else's database for the first time and I want an overall impression of "weight distribution" across database entities.

Using the Code

It's a very basic script, without any rocket surgery. :)

      TableName VARCHAR(255) ,
      RecordCount INT

EXEC sp_MSforeachtable 'INSERT #Counts (TableName, RecordCount) SELECT ''?'', COUNT(*) FROM ?';

FROM    #Counts;

SELECT  SUM(RecordCount) AS [Rows]
FROM    #Counts;

SELECT  REPLACE(REPLACE(TableName, '[', ''), ']', '') AS TableName ,
        RecordCount ,
        CAST(CAST(100.0 * RecordCount / ( SELECT    SUM(RecordCount) AS [Rows]
                                          FROM      #Counts
                                        ) AS DECIMAL(5, 2)) AS VARCHAR) + '%' AS Weight
FROM    #Counts
ORDER BY TableName ,
        RecordCount DESC;

SELECT  REPLACE(REPLACE(TableName, '[', ''), ']', '') AS EmptyTableName ,
FROM    #Counts
WHERE   RecordCount = 0
ORDER BY TableName ,
        RecordCount DESC;


Here, we simply count the records per table and load the results into a temporary table. From this, we can derive:

  1. The number of tables in the database
  2. The number of rows in the database (across all tables)
  3. The number of rows in each table, and
  4. The empty tables (with no rows)

The output looks like this:

Image 1

Points of Interest

Of course, the above script does not take into consideration the fact that a table might contain a small number of records and still heavily "outweigh" other tables in terms of disk space usage.

For example, a table containing one record that stores a binary copy of a 4GB video is obviously "bigger" (in terms of disk space) than a table containing one hundred records that store mailing addresses in plain text.

When this is an important consideration, you can use standard reports in SQL Server like "Disk Usage by Top Tables", or execute queries like this:

SELECT AS TableName , AS IndexName ,
        SUM(p.rows) AS RecordCount ,
        SUM(a.total_pages) AS PageCount ,
        SUM(a.used_pages) AS UsedPages ,
        SUM(a.data_pages) AS DataPages ,
        ( SUM(a.total_pages) * 8 ) / 1024 AS DiskSpaceMB ,
        ( 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
        AND i.object_id > 255
        AND i.index_id <= 1
        i.object_id ,
        i.index_id ,
ORDER BY OBJECT_NAME(i.object_id);

And here is another useful script, when you need to query for the disk size of your data and log files. (Thanks to CodeProject member @PIEBALDconsult for this one.)

  SELECT Type, SUM(size) Size
  FROM ( SELECT SUBSTRING(filename, LEN(filename) - 2, 3) Type ,
                CAST(size / 128.0 / 1024.0 AS NUMERIC(20,2)) Size
         FROM dbo.sysfiles ) T GROUP BY Type 
SELECT  @@servername AS ServerName ,
        DB_NAME() AS DatabaseName ,
FROM    ( SELECT Size DataSizeInGB FROM CTE WHERE Type = 'mdf' ) [Data]
        CROSS JOIN 
		( SELECT Size LogSizeInGB FROM CTE WHERE Type = 'ldf' ) [Log]


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Daniel Miller
Software Developer
Canada Canada
I have been doing software system development and operations for many more years than I care to count, working as an independent consultant for organizations that range from small non-profit associations in my local community to global Fortune 500 enterprises.

Most of my work is focused on the design, implementation, and operation of web-based business software. My research interests include application architecture, data modeling, and custom solutions for large-scale data management, conversion, and integration.

Comments and Discussions

-- There are no messages in this forum --
Posted 21 Nov 2015

Tagged as


13 bookmarked