Source: https://james.rhoat.com/p/database-table-size/
Site: James Rhoat
Title: Database Table Size
Description: A reusable SQL query to report row counts, total space, used space, and unused space per table and schema using sys.allocation_units.
Date: 2021-01-02

***

# Database Table Size


Capacity planning, storage forecasting, and "where did all the disk go?" investigations all start the same way: a per-table breakdown of how much space each table is actually consuming. SQL Server stores this data inside the system catalog views, but stitching the right views together to get a useful report takes more joins than feels reasonable.

The following query reports row counts and space usage for every user table in a database. It joins `sys.tables`, `sys.indexes`, `sys.partitions`, and `sys.allocation_units` to produce totals in both KB and MB.

```sql
SELECT
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    SUM(a.total_pages) * 8 AS TotalSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB,
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB,
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB
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
LEFT OUTER JOIN
    sys.schemas s ON t.schema_id = s.schema_id
WHERE
    t.NAME NOT LIKE 'dt%'
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
GROUP BY
    t.Name, s.Name, p.Rows
ORDER BY
    t.Name
```

