Generate DBCC SHOWCONTIG Commands for All SQL Server Tables
Before sys.dm_db_index_physical_stats existed, checking fragmentation across a database meant looking up every user table's object ID and running DBCC SHOWCONTIG against each one individually. This script closes that gap for the sysobjects-based era of SQL Server administration: it queries sysobjects for every table of type U, concatenates a ready-to-run DBCC SHOWCONTIG command for each one, and returns the full batch sorted alphabetically by table name — turning what would be dozens of hand-typed commands into a single copy-paste result set.
Purpose and Overview
DBCC SHOWCONTIG reports fragmentation for a single table or index at a time, returning metrics like Scan Density, Logical Scan Fragmentation, Extent Scan Fragmentation, and Average Page Density. Run in isolation, it answers "is this one table fragmented?" On a database with dozens or hundreds of user tables, the practical question is broader — which tables need attention this week — and answering that manually means writing one DBCC SHOWCONTIG (table_id) statement per table by hand, looking up each object ID first.
This script removes that manual lookup step entirely. sysobjects is a system table (retained today as a backward-compatibility view over the catalog views) that carries one row per database object — tables, views, stored procedures, triggers, and more — along with its object id and a type code identifying what kind of object it is. Filtering type = 'U' isolates user tables specifically, excluding system tables, views, and every other object type that would otherwise clutter the output.
The result of the query isn't data about fragmentation — it's a batch of executable T-SQL. Each row in the output is a string built by concatenating the literal text DBCC SHOWCONTIG (, the table's numeric ID converted to text, and a closing ) followed by a GO batch separator. Copy the result set into a query window and it becomes a script that runs DBCC SHOWCONTIG against every user table in the database in one pass, ordered alphabetically for easy scanning.
Code Breakdown
The script is a single SELECT statement that never touches fragmentation data directly — it only builds the commands that will.
1select 'DBCC SHOWCONTIG (' + CONVERT(varchar(12), id) + ')' + 'go'
2from sysobjects
3where type = 'U'
4order by name
String concatenation and the CONVERT function
sysobjects.id is an int column, and T-SQL's + concatenation operator requires matching or implicitly convertible types on both sides. CONVERT(varchar(12), id) turns the numeric object ID into text before it's spliced between the literal 'DBCC SHOWCONTIG (' and ')' strings. varchar(12) is generous headroom — SQL Server object IDs are 4-byte integers, so the maximum possible value never exceeds 11 characters including a leading negative sign, which some system and compatibility-view object IDs can carry.
Filtering to user tables with type = 'U'
The type column in sysobjects uses two-character codes to classify every row: 'U' for user tables, 'V' for views, 'P' for stored procedures, 'S' for system tables, and several others for triggers, defaults, and constraints. WHERE type = 'U' is what keeps this script scoped to actual data tables rather than generating nonsensical DBCC SHOWCONTIG calls against views or procedures, which the command doesn't operate on.
The missing line break — a practical gotcha
The script concatenates ')' directly against the literal 'go' with no space and, more importantly, no line break between one row's output and the next row's output. GO is a batch separator recognized by SQL Server Management Studio and sqlcmd, not the database engine itself, and it only works when it appears alone on its own line. Viewed in the SSMS results grid, each row looks like a clean, separate line — but that's a grid-rendering artifact, not an actual newline character in the string. Copy multiple rows out of the grid and paste them into a query window, and depending on how the paste handles row boundaries, the commands can land concatenated on a single line with go sitting mid-string instead of on its own line, which breaks batch parsing. Switching SSMS to Results to Text (Ctrl+T) before running the query avoids this, because text-mode results preserve a genuine newline between rows.
Modernizing the script: sys.tables and WITH TABLERESULTS
sysobjects still works in current SQL Server versions as a compatibility view, but sys.tables and sys.objects are the catalog views Microsoft has recommended since SQL Server 2005, and they don't share sysobjects' mixed-object-type design. The same idea rewritten against sys.tables, using object_id instead of id and adding a real CHAR(13) line break plus the WITH TABLERESULTS option:
1SELECT 'DBCC SHOWCONTIG (' + CONVERT(varchar(12), object_id) + ') WITH TABLERESULTS' + CHAR(13) + 'GO'
2FROM sys.tables
3ORDER BY name
WITH TABLERESULTS changes DBCC SHOWCONTIG's output from a block of narrative text messages into a proper result set with named columns — Pages, Extents, ScanDensity, LogicalFragmentation, and the rest — which is what makes it possible to insert the output into a temp table or a history table for trend tracking instead of reading free text off the screen.
Automating execution with dynamic SQL
Rather than generating commands to copy and run manually, the same sysobjects query can build one large batch string and execute it directly with sp_executesql:
1DECLARE @sql NVARCHAR(MAX) = ''
2SELECT @sql = @sql + 'DBCC SHOWCONTIG (' + CONVERT(varchar(12), id) + ') WITH TABLERESULTS' + CHAR(13) + 'GO' + CHAR(13)
3FROM sysobjects
4WHERE type = 'U'
5ORDER BY name
6
7EXEC sp_executesql @sql
This is convenient for a one-off run, but it loses the review step the original two-part workflow — generate, then eyeball, then execute — gives a DBA. On a database with an unusual or unexpected table inventory, seeing the generated command list before running it is often worth the extra click.
Key Benefits and Use Cases
- Automated command generation — replaces manually writing one
DBCC SHOWCONTIGcall per table with a single query that scales to any number of tables. - Comprehensive coverage — the
type = 'U'filter guarantees every user table is included; nothing gets skipped because a DBA forgot to look it up. - Ready-to-execute output — the generated text already includes the
GOseparator, so (line-break caveats aside) it pastes directly into a new query window. - Cross-version reach —
sysobjectsis retained as a compatibility view, so this pattern still runs on instances where team habits or older scripts still reference it. - Baseline snapshotting — running the generated batch before and after an index maintenance window produces a before/after fragmentation comparison with no extra setup.
- A stepping stone to automation — the same
sysobjects-to-sys.tablesmigration path shown here applies to any script still written against the legacy system tables.
Performance Considerations
- DBCC SHOWCONTIG is a scan-based command: it reads pages to compute its fragmentation metrics, so running it against every table in a large database can generate meaningful I/O — schedule full-database runs outside peak query windows.
sysobjectsis a compatibility view, not the current catalog: Microsoft has directed script authors towardsys.objects,sys.tables, and related catalog views since SQL Server 2005; new scripts should be written against those rather than extendingsysobjectsusage.- Free-text output without WITH TABLERESULTS is hard to automate: the original script's plain-text
DBCC SHOWCONTIGoutput can't be inserted into a table for trending without parsing; addWITH TABLERESULTSif the goal is anything beyond a one-time read. - Object IDs are instance-specific: a table's
id/object_idis not guaranteed to be the same across a restore or a copy to a different instance, so generated command lists shouldn't be cached or reused across environments — regenerate them fresh against the target database. - Running the full batch blocks nothing by design, but adds load:
DBCC SHOWCONTIGwithout repair options is a read operation and won't lock out writers the way an index rebuild would, but dozens of sequential scans back-to-back still add sustained disk read pressure on a busy instance.
Practical Tips
- Switch SSMS to Results to Text (
Ctrl+T) before copying the generated command list — it preserves real line breaks between rows and avoids the concatenated-GOproblem described above. - Add
WITH TABLERESULTSto the generated commands whenever the output needs to feed a history table or an automated fragmentation report, rather than being read as plain text. - Prefer generating against
sys.tablesfor any new script; keep thesysobjectsversion only for maintaining scripts already written against it. - When fragmentation results come back, lighter fragmentation generally warrants a
REORGANIZE, while heavier fragmentation warrants aREBUILD— the exact thresholds and trade-offs are covered in Microsoft's index maintenance guidance linked below. - On current SQL Server versions, treat this script as a stopgap rather than a destination:
sys.dm_db_index_physical_statsreturns the same fragmentation picture (and more — per-index and per-partition detail) directly as structured rows, with no command-generation step required at all.
Conclusion
This script's value is in the step it removes — looking up object IDs and hand-writing a DBCC SHOWCONTIG call per table — not in any special fragmentation logic of its own. The sysobjects version keeps working on instances where legacy habits or older tooling still expect it, while the sys.tables-plus-WITH TABLERESULTS variant and the dynamic-SQL execution wrapper both move toward a more current, more automatable setup. For ongoing fragmentation monitoring on a modern instance, sys.dm_db_index_physical_stats remains the direct path; this script earns its place as the quick, dependency-free option when that DMV isn't the workflow already in place.
References
- DBCC SHOWCONTIG (Transact-SQL) - SQL Server | Microsoft Learn — Full command reference, including the
WITH TABLERESULTSoption and the fragmentation metric columns it returns. - SQL Metadata in sys.databases, sys.objects, sys.tables and sys.columns — Walkthrough of the modern catalog views that replace the legacy
sysobjects/syscolumnscompatibility views. - Query SQL Server sys.objects for Database Objects Information — Practical examples of filtering
sys.objectsby type, the modern equivalent of thesysobjects.type = 'U'filter used here. - System Tables in SQL Server — Types, Uses and Examples — Background on SQL Server's system table and catalog view landscape, including where compatibility views fit.
- Optimize index maintenance to improve query performance and reduce resource consumption — Microsoft's guidance on choosing between
REORGANIZEandREBUILDbased on fragmentation level, and onsys.dm_db_index_physical_statsas the current diagnostic path.
Posts in this series
- Generate DBCC SHOWCONTIG Commands for All SQL Server Tables
- DBCC DBREINDEX: SQL Server Index Rebuild Script
- SQL Server DBCC DBREINDEX with Timing: Index Maintenance
- SQL Server Index Fragmentation: dm_db_index_physical_stats
- SQL Server DBCC CHECKDB Last Run Date Report
- SQL Server VLF Count Report: Virtual Log File Analysis
- SQL Server Duplicate and Overlapping Index Detection Script
- DBCC DBREINDEX vs ALTER INDEX REBUILD in SQL Server
- SQL Server DBCC SHRINKDATABASE: When and When Not to Shrink
- SQL Server DBCC CHECKDB: Complete Guide and Repair Options
- SQL Server DBCC Commands: The Complete DBA Reference Guide
- How to Update Statistics in SQL Server
- Apply Row and Page Compression to Tables and Indexes
- Detect Suspect Database Pages with msdb.dbo.suspect_pages