Image by The Real Estreya via Flickr
I just read Pradeep Adiga's excellent post on using DBCC CLEANTABLE to reclaim space left over after a column with a variable length type has been dropped from a table.
According to Books OnLine, the variable length data types are VARCHAR, NVARCHAR, VARCHAR(MAX), NVARCHAR(MAX), VARBINARY, VARBINARY(MAX), TEXT, NTEXT, IMAGE, SQL_VARIANT, and XML. If you drop one of these type columns from a table, SQL Server doesn't release the space it occupied; I imagine this is a speed optimization.
Thus inspired, here's a little script to run DBCC CLEANTABLE on all the user tables in the current database. You might be thinking, "How often does a column get dropped from a table, really?" The answer of course is, "It depends." On one huge (and abused) database I ran this script on, I gained 8 GB of space!
-----------------------------------------------------------------------------
-- Reclaim space from dropped variable length columns and text columns.
-----------------------------------------------------------------------------
RAISERROR('Reclaiming space from dropped variable length columns and text columns...', 10, 1) WITH NOWAIT
DECLARE @TableName sysname = ''
DECLARE @SchemaName sysname = ''
DECLARE cur CURSOR FOR
SELECT SCHEMA_NAME(schema_id) AS 'SchemaName'
, name AS 'TableName'
FROM sys.tables
WHERE is_ms_shipped = 0
AND type_desc = 'USER_TABLE'
ORDER BY 'SchemaName', 'TableName'
OPEN cur
FETCH NEXT FROM cur INTO @SchemaName, @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @TableName = @SchemaName + '.' + @TableName
RAISERROR(' Examining table %s', 10, 1, @TableName) WITH NOWAIT
DBCC CLEANTABLE(0, @TableName, 100000) WITH NO_INFOMSGS
FETCH NEXT FROM cur INTO @SchemaName, @TableName
END
CLOSE cur
DEALLOCATE cur
RAISERROR('Done.', 10, 1) WITH NOWAIT
Note that we specify a "batch_size" value of 100,000 rows per transaction to keep the logfile small while processing, and to keep the table locks (!) short. The appropriate value for a given system will require some experimentation: for mine, it stopped getting faster at 100,000 rows. Also, BOL points out that this script does not need to be run on a regular basis, just when a variable length or text column is dropped: but how often that actually is depends on your environment.
2 comments:
Excellent! Thank you! This saved me lots of time.
I'm surprised this hasn't received more thanks. This is a really useful tool. Thanks for sharing.
Post a Comment