Table Disk Space Usage By Filegroup and Partition
I wanted a more granular level of detail when looking at disk space usage of our databases. I wanted to see the disk usage of each table. Since we use partitioning pretty heavily I also wanted to see how that usage was broken out by partition and filegroup. In our implementation we have a separate filegroup for each table partition but in a configuration that has multiple parititons on a partition this script can tell you usage for either metric.
Normally I’ll take this query and take the results over to excel and pivot the data so that I can filter and sum data in whatever way I want. I also have this running in a SQL Agent job and inserting into a table so that I connect to that table and do growth trend analysis.
Note: I’ve commented out the last line of the WHERE clause in this script to show both data and index stats. If you uncomment that line you will see just Data usage. If you don’t uncomment that line you’ll have to remember to filter your results by the “Type” column so that you don’t duplicate your storage statistics.
Here’s a quick explanation of the data columns I’m pulling in.
By default data pages in MSSQL are 8KB and that’s the assumption that I’m making with this query.
- Used_Pages: the number of pages actually used by the table including non-leaf B-tree pages and IAM pages.
- Reserved_Pages: is the number of pages being reserved in total for the object, whether used or not.
- Data_Pages: the number of pages being used excluding non-leaf B-tree pages.
here’s a link to the BOL page that describes these: http://msdn.microsoft.com/en-us/library/ms187737.aspx
SELECT DB_NAME() AS 'DatabaseName' ,OBJECT_NAME(p.OBJECT_ID) AS 'TableName' ,p.index_id AS 'IndexId' ,CASE WHEN p.index_id = 0 THEN 'HEAP' ELSE i.name END AS 'IndexName' ,p.partition_number AS 'PartitionNumber' ,prv_left.value AS 'LowerBoundary' ,prv_right.value AS 'UpperBoundary' ,CASE WHEN fg.name IS NULL THEN ds.name ELSE fg.name END AS 'FileGroupName' ,CAST(p.used_page_count * 0.0078125 AS NUMERIC(18,2)) AS 'UsedPages_MB' ,CAST(p.in_row_data_page_count * 0.0078125 AS NUMERIC(18,2)) AS 'DataPages_MB' ,CAST(p.reserved_page_count * 0.0078125 AS NUMERIC(18,2)) AS 'ReservedPages_MB' ,CASE WHEN p.index_id IN (0,1) THEN p.row_count ELSE 0 END AS 'RowCount' ,CASE WHEN p.index_id IN (0,1) THEN 'data' ELSE 'index' END 'Type' FROM sys.dm_db_partition_stats p INNER JOIN sys.indexes i ON i.OBJECT_ID = p.OBJECT_ID AND i.index_id = p.index_id INNER JOIN sys.data_spaces ds ON ds.data_space_id = i.data_space_id LEFT OUTER JOIN sys.partition_schemes ps ON ps.data_space_id = i.data_space_id LEFT OUTER JOIN sys.destination_data_spaces dds ON dds.partition_scheme_id = ps.data_space_id AND dds.destination_id = p.partition_number LEFT OUTER JOIN sys.filegroups fg ON fg.data_space_id = dds.data_space_id LEFT OUTER JOIN sys.partition_range_values prv_right ON prv_right.function_id = ps.function_id AND prv_right.boundary_id = p.partition_number LEFT OUTER JOIN sys.partition_range_values prv_left ON prv_left.function_id = ps.function_id AND prv_left.boundary_id = p.partition_number - 1 WHERE OBJECTPROPERTY(p.OBJECT_ID, 'ISMSSHipped') = 0 --AND p.index_id in (0,1)
Thanks a million! This is exactly what I was looking for.
Yes, thanks from me too!
Just finished the section on Partitions in the MOC training and realised as I worked through the exercises that nothing was stated about how to retrieve a not insignificant piece of info… The link between a file group and it’s associated partion\s
Tnx!