Check Multiple Databases Quickly
If you work in a shop with many SQL Servers, you’ve either already dealt with a storage issue or you will. Storage controllers going down, unexpected shutdowns, someone hitting the power button on a database server — all of these are good ways to end up with corruption. That’s why weekly DBCC checks are non-negotiable, but sometimes you need to run ad-hoc checks across a lot of databases quickly.
I ran into this situation after a storage controller failure knocked down several SQL instances. The task: check a large number of smaller databases for corruption quickly without blocking everything else for hours. The approach we settled on:
- Physical-only checks with
DBCC CHECKDB(faster, still catches page corruption) - Only target databases under 1GB (larger ones could be queued separately)
- Dynamic SQL so it could run across multiple servers via a management tool
Here’s the script:
-- store database names under 1GB (data files only)DECLARE @dbcc_physical TABLE ( name NVARCHAR(128) NOT NULL);
INSERT INTO @dbcc_physicalSELECT d.nameFROM sys.databases dINNER JOIN sys.master_files f ON d.database_id = f.database_id AND f.type = 0WHERE d.name NOT IN ('master', 'model', 'msdb', 'tempdb')GROUP BY d.nameHAVING SUM(f.size) < 131072; -- 131072 pages * 8KB = 1GB
-- cursor to run DBCC CHECKDB on each databaseDECLARE @tableCursor CURSOR;15 collapsed lines
DECLARE @databaseName NVARCHAR(128);
SET @tableCursor = CURSOR FOR SELECT name FROM @dbcc_physical;
OPEN @tableCursor;FETCH NEXT FROM @tableCursor INTO @databaseName;
WHILE (@@FETCH_STATUS = 0)BEGIN EXECUTE ('DBCC CHECKDB(' + QUOTENAME(@databaseName) + ') WITH PHYSICAL_ONLY;'); FETCH NEXT FROM @tableCursor INTO @databaseName;END;
CLOSE @tableCursor;DEALLOCATE @tableCursor;A few notes on the implementation:
sys.master_filesstores size in 8KB pages, so131072pages = 1GB. The original version usedsize < 1024which filtered to databases under ~8MB — far too small.sys.databasesgives you the database name;sys.master_filesgives you the file sizes. You need to join them — queryingnamedirectly fromsys.master_filesreturns the logical file name, not the database name.QUOTENAME()wraps the database name to handle spaces or special characters safely.PHYSICAL_ONLYskips logical consistency checks and focuses on structural integrity — significantly faster, appropriate for routine or recovery triage checks.
Adjust the size threshold and the system database exclusion list to fit your environment.
Key Takeaways
sys.master_files.sizeis in 8KB pages — multiply by 8192 to get bytes, or compare to131072for a 1GB threshold.- Use
sys.databasesfor database names, notsys.master_files.name(which is the logical file name). DBCC CHECKDB WITH PHYSICAL_ONLYis significantly faster and appropriate for triage or high-volume checks.QUOTENAME()is non-optional when building dynamic SQL with database names.