Query Tuning

Breaking complex logic with CTEs and temp tables

Stage intermediate results so the optimizer can estimate each step honestly.

SQL diagnosticTempDB configuration diagnostictempdb_configuration.sql
Download .sql
/*
================================================================================
Purpose:        Analyzes TempDB file allocations (file counts, uniformity of 
                sizes/growths) and identifies PAGELATCH allocation bottlenecks.
Provides:       TempDB file counts, growth uniformity, active PAGELATCH 
                contention.
Importance:     TempDB is a shared resource; contention here bottlenecks the 
                entire instance.
 Interpretation: Files should match cores (up to 8). Mismatched growth is 
                critical. PAGELATCH waits indicate contention.
Action:         If file count < @ExpectedFiles, add equal-sized data files (1 per core/CPU up to 8). If file sizes are not uniform, resize all files to the same size. If PAGELATCH waits are detected, adding files often resolves allocation contention. Restart is NOT required after adding TempDB files.
Criticality:    High
Author:        Ravi Sharma
================================================================================
*/

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON;

-- 1. TempDB File Configuration Analysis
PRINT '--- TempDB File Configuration & Uniformity ---';
DECLARE @LogCores INT = (SELECT cpu_count FROM sys.dm_os_sys_info);
DECLARE @ExpectedFiles INT = CASE WHEN @LogCores <= 8 THEN @LogCores ELSE 8 END;

SELECT 
    name AS [Logical_File_Name],
    type_desc AS [File_Type],
    size * 8 / 1024 AS [Size_MB],
    growth AS [Growth_Value],
    is_percent_growth AS [Is_Percent_Growth],
    CASE 
        WHEN is_percent_growth = 1 THEN '🔴 CRITICAL: Use fixed-size growth (e.g. 256MB) to ensure uniformity.'
        WHEN growth <> (SELECT TOP 1 growth FROM sys.master_files WHERE database_id = 2 AND type = 0 ORDER BY file_id) 
             THEN '🔴 CRITICAL: Mismatched growth increments will break proportional fill.'
        ELSE '🟢 OPTIMAL'
    END AS [Growth_Uniformity_Status],
    (SELECT COUNT(*) FROM sys.master_files WHERE database_id = 2 AND type = 0) AS [Data_Files_Count],
    @ExpectedFiles AS [Target_Data_Files],
    CASE 
        WHEN (SELECT COUNT(*) FROM sys.master_files WHERE database_id = 2 AND type = 0) < @ExpectedFiles 
             THEN '🟡 WARNING: File count should match logical cores up to 8.'
        ELSE '🟢 OPTIMAL'
    END AS [File_Count_Status]
FROM sys.master_files WITH (NOLOCK)
WHERE database_id = 2; -- TempDB database_id is 2

-- 2. Detect TempDB PAGELATCH Contention (PFS, GAM, SGAM)
PRINT '--- Active TempDB PAGELATCH Contention (Allocation Pages) ---';
SELECT 
    session_id,
    wait_type,
    wait_duration_ms,
    resource_description,
    CASE 
        WHEN resource_description LIKE '2:%:1' OR resource_description LIKE '2:%:125440' THEN '🔴 CRITICAL: PFS page contention. More files or uniform growth needed.'
        WHEN resource_description LIKE '2:%:2' THEN '🔴 CRITICAL: GAM page contention.'
        WHEN resource_description LIKE '2:%:3' THEN '🔴 CRITICAL: SGAM page contention.'
        ELSE '⚪ INFO: Other Page Contention'
    END AS [Expert_Guidance]
FROM sys.dm_os_waiting_tasks WITH (NOLOCK)
WHERE wait_type LIKE 'PAGELATCH_%'
  AND resource_description LIKE '2:%'; -- Database 2 is TempDB

-- 3. Historical Allocation Contention (Waits)
PRINT '--- Historical Allocation Contention (Waits) ---';
SELECT 
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    CASE 
        WHEN wait_type IN ('PAGELATCH_UP', 'PAGELATCH_EX', 'PAGELATCH_SH') THEN '🟡 WARNING: Potential TempDB Metadata/Allocation bottleneck'
        ELSE '🟢 NORMAL'
    END AS [Wait_Status]
FROM sys.dm_os_wait_stats
WHERE wait_type LIKE 'PAGELATCH_%'
  AND waiting_tasks_count > 0
ORDER BY wait_time_ms DESC;

Review the full script and confirm the connected SQL Server instance before execution. The run instructions and output guide appear later in this article.

Diagram for Breaking complex logic with CTEs and temp tables
Breaking complex logic with CTEs and temp tables

Dummy guide: nested views and mega-queries hide bad estimates.

Rewrite the monster into named CTE stages for humans, then materialize expensive stages into #temp tables when the optimizer keeps underestimating. Index the temp when the next step filters or joins on it more than once.

Do not assume every CTE is materialized — in SQL Server it usually is not. Measure with actual plans, not folklore.

Why intermediate result design deserves a method

The central principle is that CTEs improve expression but do not automatically materialize or create statistics. A single metric, recommendation, or successful command is not enough. The decision has to connect an observed symptom to a plausible cause, a controlled change, and a result that can be verified under the workload that matters.

Evidence to collect

Use evidence from the same time window whenever possible:

  • estimated versus actual rows
  • repeated references to the intermediate result
  • tempdb cost and indexing opportunity
  • compile behavior and parameter skew

A practical workflow

  1. Start with the simplest correct query.
  2. Inspect the actual plan and estimates.
  3. Test a temporary-table breakpoint when estimates diverge.
  4. Compare reads, CPU, duration, and concurrency.

Common mistakes

Avoid these shortcuts:

  • assuming every CTE is materialized
  • replacing all CTEs with temp tables
  • testing only one parameter value

Verification and completion

Define completion before making the change. Confirm correctness first, then compare latency, throughput, reads, CPU, waits, storage behavior, or recovery time as appropriate for Breaking complex logic with CTEs and temp tables. Test negative and boundary cases, not only the path expected to succeed. Watch the system long enough to cover the relevant workload pattern.

Download and run the diagnostic

TempDB configuration diagnostic

Download tempdb_configuration.sql

Before you run it

  • Review every statement and confirm the connection points to the intended SQL Server database server.
  • Run through a non-production or read-only diagnostic account first when possible.
  • Required access: VIEW SERVER STATE.
  • Save the output with the server name, database name, collection time, and workload window so another engineer can reproduce the analysis.

What it does

Reports TempDB files, size, growth, placement, and configuration signals relevant when temporary objects or spills become part of a rewrite. The script is diagnostic and does not apply an automatic remediation. Result values still need workload context, a second supporting signal, and a before-and-after comparison.

How to read the output values

Compare file sizes and growth increments. Uneven sizes can undermine proportional fill. Small growth increments can cause repeated pauses. This output describes TempDB capacity; use an actual plan and task-space DMVs to prove that a CTE or temporary-table choice drives the load.