Query Tuning
Table variables for small, known rowsets
Keep tiny lookup sets in memory — and know when a temp table is safer.
/*
================================================================================
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.
Dummy guide: table variables are not "faster temp tables."
Use @table when the row count is small and predictable (config lists, id batches under a few
hundred). Prefer #temp when cardinality is unknown, when you need statistics-driven plans, or
when you will index intermediate results.
On modern SQL Server versions, deferred compilation helps table variables — still verify with actual row counts before promoting a pattern across the codebase.
Why table variable choice deserves a method
The central principle is that table variables can be effective for genuinely small intermediate sets, but row estimates and repeated access still matter. 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:
- actual row count and variation
- compatibility level and deferred compilation
- join choices and spills
- need for indexes or statistics
A practical workflow
- Measure the intermediate cardinality.
- Inspect estimates and downstream operators.
- Compare a temporary table for larger or unstable sets.
- Test across representative parameter values.
Common mistakes
Avoid these shortcuts:
- using a fixed row-count rule
- assuming memory-only storage
- ignoring repeated scans and missing indexes
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 Table variables for small, known rowsets. 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.sqlBefore 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
Shows TempDB file and growth configuration that forms the storage boundary for table variables, temporary tables, spills, and version-store activity. 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
Check equal file size and growth, available capacity, and sensible fixed growth. This output does not decide between a table variable and a temp table; combine it with actual cardinality, estimates, spills, and plan behavior.