Problem
One thing that is often handy is to know how much space each table is using within your database. It is helpful to know the number of rows, the data space used as well as the index space used. There are several ways that you can get this information, by reading the system tables, using SSMS and using the built-in reports in SSMS. In this tip we look at some queries that can be used to do this.
Solution
There are several ways to pull the data to find out the space used for a table. One simple way to do this is to use sp_spaceused to get the space used for a table. We will use the AdventureWorks database for this test.
sp_spaceused Example
Here is the simple command to get the data for one table.
sp_spaceused '[HumanResources].[Department]'This returns the following information:

This is great if you want to do one table at a time, but what if you want to do all of the tables. You can use this code as suggested in the comments section:
DECLARE @str VARCHAR(500)
SET @str = 'exec sp_spaceused ''?'''
EXEC sp_msforeachtable @command1=@strThis is helpful, but the output is not very easy to read.

Better way to analyze sp_spaceused data
So, what if we put the results to a temp table as shown in the comments section and then we could sort the data as needed like this:
CREATE TABLE #SpaceUsed (
TableName sysname
,NumRows BIGINT
,ReservedSpace VARCHAR(50)
,DataSpace VARCHAR(50)
,IndexSize VARCHAR(50)
,UnusedSpace VARCHAR(50)
)
DECLARE @str VARCHAR(500)
SET @str = 'exec sp_spaceused ''?'''
INSERT INTO #SpaceUsed
EXEC sp_msforeachtable @command1=@str
SELECT * FROM #SpaceUsed ORDER BY TableNameWhen we run this we get the following output sorted by table name:

This is great, but if we try to sort by ReservedSpace as follows.
SELECT * FROM #SpaceUsed ORDER BY ReservedSpace descThe sorting doesn’t work correctly. It thinks ResevedSpace is a text column, so it sorts in text order, not numerical order.

Using sp_spaceused with real numbers
So, what we can do is convert all of the space columns to numbers, by removing the KB and also converting the values to MB instead of KB as follows.
SELECT TableName, NumRows,
CONVERT(numeric(18,0),REPLACE(ReservedSpace,' KB','')) / 1024 as ReservedSpace_MB,
CONVERT(numeric(18,0),REPLACE(DataSpace,' KB','')) / 1024 as DataSpace_MB,
CONVERT(numeric(18,0),REPLACE(IndexSize,' KB','')) / 1024 as IndexSpace_MB,
CONVERT(numeric(18,0),REPLACE(UnusedSpace,' KB','')) / 1024 as UnusedSpace_MB
FROM #SpaceUsed
ORDER BY ReservedSpace_MB descNow the sorting will work correctly as follows:

Script to get sortable space used info for all SQL Server tables in a database
Here is the complete script. You can change the ORDER BY as needed.
IF OBJECT_ID('tempdb..#SpaceUsed') IS NOT NULL
DROP TABLE #SpaceUsed
CREATE TABLE #SpaceUsed (
TableName sysname
,NumRows BIGINT
,ReservedSpace VARCHAR(50)
,DataSpace VARCHAR(50)
,IndexSize VARCHAR(50)
,UnusedSpace VARCHAR(50)
)
DECLARE @str VARCHAR(500)
SET @str = 'exec sp_spaceused ''?'''
INSERT INTO #SpaceUsed
EXEC sp_msforeachtable @command1=@str
SELECT TableName, NumRows,
CONVERT(numeric(18,0),REPLACE(ReservedSpace,' KB','')) / 1024 as ReservedSpace_MB,
CONVERT(numeric(18,0),REPLACE(DataSpace,' KB','')) / 1024 as DataSpace_MB,
CONVERT(numeric(18,0),REPLACE(IndexSize,' KB','')) / 1024 as IndexSpace_MB,
CONVERT(numeric(18,0),REPLACE(UnusedSpace,' KB','')) / 1024 as UnusedSpace_MB
FROM #SpaceUsed
ORDER BY ReservedSpace_MB descDownside to using sp_spaceused
One of the major downsides to using sp_spaceused is that it only returns the table name and does not include the schema name. So, if you have several tables with the same name, but with different schemas it is kind of hard to tell which table it is.
Next Steps
- Add these scripts to your toolbox
- Run these scripts on a set schedule like once a week or once a month to get a handle on how your database and tables are changing. This can then be used for trending and space requirements as you do future planning for your database.
- Get SQL Server Row Count and Space Used with the sp_rows
- Determine space used for a table using SQL Server Management Studio

Greg Robidoux has been working with databases for 35+ years with extensive hands on SQL Server experience from version 6.5 to 2025. He has authored over 250 technical articles and delivered several presentations online and at various conventions. Greg is also the President and founder of Edgewood Solutions, a technology services company delivering services and solutions for Microsoft SQL Server.



Thanks Steve.
There is another way (probably faster) to extract this information directly from system tables instead of calling repeatedly the sp_spaceused procedure.
I extracted the query from the “Disk usage by table” standard report.
SELECT
a3.name AS [schemaname],
a2.name AS [tablename],
a1.rows as row_count,
(a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved,
a1.data * 8 AS data,
(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) – a1.data ELSE 0 END) * 8 AS index_size,
(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) – a1.used ELSE 0 END) * 8 AS unused
FROM
(SELECT
ps.object_id,
SUM (
CASE
WHEN (ps.index_id < 2) THEN row_count
ELSE 0
END
) AS [rows],
SUM (ps.reserved_page_count) AS reserved,
SUM (
CASE
WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
END
) AS data,
SUM (ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN
(SELECT
it.parent_id,
SUM(ps.reserved_page_count) AS reserved,
SUM(ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
WHERE it.internal_type IN (202,204)
GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2 ON ( a1.object_id = a2.object_id )
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N’S’ and a2.type <> N’IT’
ORDER BY 4 desc
Hi Sana,
you would need to build a table to store historical data and set up a scheduled job to periodically capture the data. Then you could do comparisons of different points in time.
This is great, Is there any way we get the historical changes in this specific table. Like How many rows added 1 year back, and how much space used that time, and How many rows were added a month ago like that
Thanks Greg, just what I was looking for this morning!
Hello, I found a query
EXEC sp_MSforeachdb ‘USE ?
EXEC sp_spaceused @oneresultset = 1;
Hi S,
the only way to figure that out would be to run this process each day to collect the data and then put together some queries to do a differential between dates.
How can we get to know the space used for one particular date?