Last Year I introduced a couple of scripts that I worked on. Those scripts developed into a series covering the comparison of some methods and MS provided stored procs that could help you in the retrieval of table sizes in SQL Server.
I pulled out one of those scripts recently in order to find what tables, in an R and D database, were consuming alot of space. While running that script, I realized that it could easily be used to help me with an additional task. I decided that this script could help me deduce the top 10 biggest tables in a database that doesn’t necessarily need to have that data. Or maybe, I just need to clean out the data so I can test populating the database. This script is predicated on a lack of foreign keys – but can easily be adapted.
So, in all of its glory:
/*similar to sp_spaceused */
DECLARE @dbsize DECIMAL(19,2)
,@logsize DECIMAL(19,2)
SET NOCOUNT ON
/*
** Summary data.
*/
BEGIN
SELECT @dbsize = SUM(CONVERT(DECIMAL(19,2),CASE WHEN type = 0 THEN SIZE ELSE 0 END)) * 8/1024
, @logsize = SUM(CONVERT(DECIMAL(19,2),CASE WHEN type = 1 THEN SIZE ELSE 0 END)) * 8/1024
FROM sys.database_files
END
/*
** We want all objects.
*/
BEGIN
WITH FirstPass AS (
SELECT OBJECT_ID,
ReservedPage = CONVERT(DECIMAL(19,2),SUM(reserved_page_count)) * 8/1024,
UsedPage = CONVERT(DECIMAL(19,2),SUM(used_page_count)) *8/1024,
PageCnt = SUM(
CONVERT(DECIMAL(19,2),CASE
WHEN (index_id < 2)
THEN (used_page_count)
ELSE lob_used_page_count + row_overflow_used_page_count
END
)) * 8/1024,
RowCnt = SUM(
CASE
WHEN (index_id < 2)
THEN row_count
ELSE 0
END
)
FROM sys.dm_db_partition_stats
--Where OBJECTPROPERTY(OBJECT_ID,'IsMSShipped') = 0
GROUP BY OBJECT_ID
)
,InternalTables AS (
SELECT ps.OBJECT_ID,
ReservedPage = CONVERT(DECIMAL(19,2),SUM(reserved_page_count)) * 8/1024,
UsedPage = CONVERT(DECIMAL(19,2),SUM(used_page_count)) *8/1024
FROM sys.dm_db_partition_stats ps
INNER Join sys.internal_tables it
ON it.OBJECT_ID = ps.OBJECT_ID
And it.internal_type IN (202,204,211,212,213,214,215,216)
WHERE it.parent_id = ps.OBJECT_ID
--And OBJECTPROPERTY(ps.OBJECT_ID,'IsMSShipped') = 0
GROUP BY ps.OBJECT_ID
)
SELECT 'Truncate table ' + OBJECT_NAME (f.OBJECT_ID) + '' AS TruncTabStatement
,TableSizeMB = SUM(f.PageCnt) +
SUM(CASE WHEN (f.UsedPage + IsNull(i.UsedPage,0)) > f.PageCnt
THEN ((f.UsedPage + IsNull(i.UsedPage,0)) - f.PageCnt) ELSE 0 END)
FROM FirstPass F
LEFT Outer Join InternalTables i
ON i.OBJECT_ID = f.OBJECT_ID
WHERE OBJECTPROPERTY(f.OBJECT_ID,'IsMsShipped') = 0
GROUP BY f.OBJECT_ID
ORDER BY TableSizeMB DESC
END
I think the script, along with prior explanations, is pretty straight forward. This can quickly help reset those LARGE tables for continued testing. Of course, that is predicated on you not already having a script for that, and that you don’t know what tables need to be reset (maybe you are in a large team).
This is just one example of a script that can be useful for more than what it was first designed to do. As DB professionals, we often come across situations were a prior script can easily be repurposed for the task at hand. Knowing that, and how to do it, is an important tool in your toolbox.