sql server hub / sizing guide

SQL Server sizing guide

SQL Server sizing is not just checking database size. The goal is to find what is tight now, what will be tight next, and what the server needs before the next big change.

Use this guide to collect read-only SQL Server output for instance shape, database files, CPU pressure, memory grants, storage latency, tempdb pressure, Agent jobs, backups, growth, and platform constraints. If high availability is part of the same decision, keep the SQL Server failover guide nearby.

workload

headroom

decision

Guide

Guide~13 min readUpdated 13 Aug 2026

Share

LinkedInXEmail

Use this when

1

Size from workload output, not database size alone.

2

Separate capacity, latency, concurrency, and growth before choosing hardware.

3

Use read-only checks first; do not change settings to prove a sizing theory.

4

Document the current bottleneck, headroom, risky inputs, and next review date.

1 / Sizing target

What SQL Server sizing must answer

A sizing answer should say more than how large the databases are. It should explain which resource is tight now, which resource will become tight next, and how much headroom the setup needs for peak work, maintenance, backups, failover behavior, and growth.

The useful output is a small decision package: CPU shape, memory fit, storage capacity and latency, tempdb needs, concurrency risk, operational load, growth allowance, platform constraints, and the assumptions that still need proving.

InputWhat it provesWhat it does not prove
Database sizeHow much space exists now.Whether CPU, memory, latency, or concurrency will hold.
CPU countThe configured compute shape.Whether schedulers are under pressure at peak.
Memory settingThe instance memory ceiling.Whether the workload fits in memory well enough.
Storage capacityHow much room the files have.Whether writes, reads, backups, and tempdb are fast enough.
Average utilizationThe normal day shape.Whether month-end, batch overlap, or reporting peaks are safe.
Growth rateHow fast the footprint changes.Whether the workload, maintenance, and backup windows will still fit.

2 / Calculations

SQL Server sizing examples with numbers

People usually want a number: how much disk, memory, CPU, tempdb, backup space, or throughput. The exact number depends on the workload, but the calculation should be visible. These examples show the shape of the math before the DMV checks refine it.

Sizing questionExample inputExample calculation
Data file runwayCurrent data size 180 GB, growth 8 GB/month, planning window 18 months, headroom 25%.(180 + (8 x 18)) x 1.25 = 405 GB data capacity target.
Backup storageFull backup 110 GB compressed, keep 14 daily fulls, add 30% for diffs, logs, and job overlap.(110 x 14) x 1.30 = 2002 GB backup target, before offsite retention.
Memory starting pointVM has 64 GB RAM and only SQL Server runs there. Leave 8 GB for Windows, backup tools, AV, drivers, and headroom.64 - 8 = 56 GB max server memory starting point, then validate with grants, reads, and OS pressure.
Tempdb working spaceObserved tempdb peak 70 GB during ETL, normal peak 25 GB, add 50% incident headroom.70 x 1.5 = 105 GB tempdb space target, plus predictable growth and storage latency checks.
Maintenance throughputCHECKDB, backup, or migration copy must process 600 GB inside a 4-hour window.600 / 4 = 150 GB/hour, about 42 MB/sec sustained before concurrency, latency, and other jobs.
CPU pressure8 visible schedulers and 4 runnable tasks sustained during the business peak.Runnable work equals 50% of scheduler count. That points to CPU pressure unless one bad query or job is causing it.

Where SQL Server sizing matters most

Best practice is not one magic server shape. The useful practice is knowing which part of the system matters for this workload, then sizing that part from measured peaks and realistic growth.

AreaWhy it mattersPractical sizing rule
MemoryStarting point: leave 4 GB for Windows on small servers, 8 GB on 32-64 GB servers, 10-15% on larger dedicated servers.Example: 64 GB RAM - 8 GB reserve = 56 GB max server memory. For 256 GB RAM, start around 220-230 GB, then validate.
Storage latencyUseful targets: data reads often need < 20 ms, log writes often need < 5 ms, tempdb should usually stay < 10-15 ms under load.If a data file averages 45 ms reads or a log file averages 25 ms writes during peak, storage is part of the sizing problem.
TempdbStart with observed peak tempdb usage x 1.5. Use 4-8 equally sized data files for many busy OLTP systems; do not jump past 8 without evidence.Example: peak tempdb use 70 GB x 1.5 = 105 GB. With 8 data files, start around 13 GB each plus a separate log file.
CPUWatch sustained runnable_tasks_count. More than 1 runnable task per 4 schedulers during peak is worth investigating; 1 per 2 schedulers is serious.Example: 8 schedulers with 4 runnable tasks means 50% scheduler pressure. Do not choose fewer cores for the next platform.
Transaction logSize the log for the largest normal write burst plus 25-50% headroom. For full recovery, log backup cadence must fit RPO.Example: nightly load writes 35 GB to log. Start log around 50 GB, not 5 GB with repeated autogrowth.
Backups and restoreBackup storage = compressed full size x retained copies, plus diff/log space, plus 20-30% working headroom.Example: 110 GB full x 14 days x 1.3 = about 2 TB. Restore speed for 600 GB in 4 hours needs about 42 MB/sec sustained.
Peak concurrencySize from the busiest real 15-60 minute window, not the daily average. Track active requests, waits, CPU, and file latency in that window.Example: average CPU 25% is irrelevant if month-end holds 85-95% CPU for 45 minutes with runnable tasks and slow requests.
Growth runwayCapacity target = current size + monthly growth x months, then add 20-30% headroom. Review again when 70-80% of target is used.Example: 180 GB + 8 GB/month x 18 months = 324 GB. Add 25% headroom = 405 GB target.

SQL Server memory and MAXDOP calculator

Use this for a reviewable starting point. Reserve memory outside the instance first, then compare the result with operating-system pressure, SQL Server memory clerks, other instances, and the actual NUMA layout.

The formulas follow Microsoft's starting guidance for server memory and MAXDOP. They are starting values to test, not automatic production settings.

Host and instances

Enter the memory budget for this instance

Reserve memory for Windows and memory used outside max server memory, then enter the combined maximum assigned to the other SQL Server instances.
GB
GB
GB

Calculated baseline

Review the current instance budget

The memory result uses 75% of the amount left after the host reserve and the other instances' configured maximums. MAXDOP follows Microsoft's processor and NUMA starting table.

Available to SQL Server

104.0 GB

This instance envelope

72.0 GB

Average other-instance max

32.0 GB

Across 1 other instance

Max server memory

55,296 MB

Processors per NUMA node

16

MAXDOP starting value

8

  • Confirm every instance's configured maximum and memory use outside max server memory. The combined plan must fit inside physical memory during peak overlap.
  • MAXDOP is the top end of Microsoft's starting guidance for this processor layout. Workload testing may justify a lower value.

Review the current settings, workload peaks, and every instance budget before running this SQL.

SQL

Generated SQL Server configuration

T-SQL · 18 lines

-- Starting values only. Review current settings and workload measurements first.-- Host memory: 128 GB-- Reserved outside SQL Server max memory settings: 24 GB-- Other SQL Server instances: 1-- Combined max server memory for other instances: 32 GB-- Envelope left for this instance: 72 GBEXEC sys.sp_configure N'show advanced options', 1;RECONFIGURE; EXEC sys.sp_configure N'max server memory (MB)', 55296;EXEC sys.sp_configure N'max degree of parallelism', 8; -- Review the generated values before running this final statement.RECONFIGURE; SELECT name, value, value_in_useFROM sys.configurationsWHERE name IN (N'max server memory (MB)', N'max degree of parallelism');
Review before runningT-SQLUTF-818 lines

3 / Context

SQL Server capacity planning inputs

Start with instance identity, version, edition, uptime, CPU count, scheduler count, physical memory, and virtualization state. Many DMV readings reset when SQL Server restarts, so a five-hour uptime and a five-month uptime should not be interpreted the same way.

Reads version, edition, uptime, CPU, scheduler, memory, and virtualization context.

SQL

Instance shape and uptime

T-SQL · 17 lines

SELECT    @@SERVERNAME AS server_name,    SERVERPROPERTY(N'MachineName') AS machine_name,    SERVERPROPERTY(N'InstanceName') AS instance_name,    SERVERPROPERTY(N'Edition') AS edition,    SERVERPROPERTY(N'ProductVersion') AS product_version,    SERVERPROPERTY(N'ProductLevel') AS product_level,    SERVERPROPERTY(N'ProductUpdateLevel') AS product_update_level,    SERVERPROPERTY(N'EngineEdition') AS engine_edition,    si.sqlserver_start_time,    DATEDIFF(hour, si.sqlserver_start_time, SYSDATETIME()) AS uptime_hours,    si.cpu_count,    si.scheduler_count,    si.hyperthread_ratio,    si.physical_memory_kb / 1024 AS physical_memory_mb,    si.virtual_machine_type_descFROM sys.dm_os_sys_info AS si;
Review before runningT-SQLUTF-817 lines

uptime_hours tells you how much history the DMV counters can represent. scheduler_count is the SQL Server scheduler shape visible to the instance. virtual_machine_type_desc helps separate assigned hardware from virtualized resource behavior. Edition can affect capacity limits and feature choices.

Reads common capacity-related instance settings before judging the workload.

SQL

CPU and memory configuration

T-SQL · 13 lines

SELECT    name,    value AS configured_value,    value_in_use,    descriptionFROM sys.configurationsWHERE name IN (    N'max server memory (MB)',    N'min server memory (MB)',    N'max degree of parallelism',    N'cost threshold for parallelism')ORDER BY name;
Review before runningT-SQLUTF-813 lines

value and value_in_use can differ when a setting is configured but not active yet. max server memory should be read with OS and workload context, not as a standalone rule. Parallelism settings affect CPU pressure interpretation. Do not change these during collection just to see what happens.

4 / Files and growth

SQL Server database size and growth planning

File size is still important. It affects storage, backups, restores, CHECKDB, migration timing, and growth runway. But file size is an input. It does not prove that CPU, memory, tempdb, latency, or concurrency are safe.

Summarizes user database size, recovery model, compatibility level, and Query Store state.

SQL

Database size and recovery context

T-SQL · 21 lines

SELECT    d.name AS database_name,    d.state_desc,    d.recovery_model_desc,    d.compatibility_level,    d.is_query_store_on,    COUNT(mf.file_id) AS file_count,    CONVERT(decimal(18,2), SUM(mf.size) / 128.0) AS total_size_mb,    CONVERT(decimal(18,2), SUM(CASE WHEN mf.type = 0 THEN mf.size ELSE 0 END) / 128.0) AS data_size_mb,    CONVERT(decimal(18,2), SUM(CASE WHEN mf.type = 1 THEN mf.size ELSE 0 END) / 128.0) AS log_size_mbFROM sys.databases AS dJOIN sys.master_files AS mf    ON mf.database_id = d.database_idWHERE d.name NOT IN (N'master', N'model', N'msdb', N'tempdb')GROUP BY    d.name,    d.state_desc,    d.recovery_model_desc,    d.compatibility_level,    d.is_query_store_onORDER BY total_size_mb DESC;
Review before runningT-SQLUTF-821 lines

Large databases affect backup, restore, CHECKDB, migration, and storage planning. Recovery model changes log behavior and backup requirements. Compatibility level can matter during upgrade or workload-change sizing. Query Store state tells you whether richer workload history may be available.

Lists data, log, and tempdb file paths, sizes, growth settings, and max size.

SQL

File layout and growth settings

T-SQL · 21 lines

SELECT    DB_NAME(mf.database_id) AS database_name,    mf.file_id,    mf.type_desc,    mf.name AS logical_name,    mf.physical_name,    CONVERT(decimal(18,2), mf.size / 128.0) AS size_mb,    CASE        WHEN mf.is_percent_growth = 1            THEN CONCAT(mf.growth, N'%')        ELSE CONCAT(CONVERT(decimal(18,2), mf.growth / 128.0), N' MB')    END AS growth_setting,    CASE        WHEN mf.max_size = -1 THEN N'Unlimited'        WHEN mf.max_size = 0 THEN N'No growth'        ELSE CONCAT(CONVERT(decimal(18,2), mf.max_size / 128.0), N' MB')    END AS max_size,    mf.is_percent_growthFROM sys.master_files AS mfWHERE DB_NAME(mf.database_id) NOT IN (N'master', N'model', N'msdb')ORDER BY DB_NAME(mf.database_id), mf.type_desc, mf.file_id;
Review before runningT-SQLUTF-821 lines

Percent growth can create unpredictable growth events as files get larger. Physical paths show whether files share storage that should be treated separately. Unlimited max size still depends on real disk capacity and alerting. Growth settings explain some incidents but do not replace workload sizing.

Reads current log usage and reuse wait reason for each user database.

SQL

Transaction log pressure

T-SQL · 11 lines

SELECT    d.name AS database_name,    d.recovery_model_desc,    d.log_reuse_wait_desc,    CONVERT(decimal(18,2), ls.total_log_size_mb) AS total_log_size_mb,    CONVERT(decimal(18,2), ls.used_log_space_mb) AS used_log_space_mb,    CONVERT(decimal(9,2), ls.used_log_space_in_percent) AS used_log_space_percentFROM sys.databases AS dCROSS APPLY sys.dm_db_log_stats(d.database_id) AS lsWHERE d.name NOT IN (N'master', N'model', N'msdb', N'tempdb')ORDER BY ls.used_log_space_in_percent DESC;
Review before runningT-SQLUTF-811 lines

log_reuse_wait_desc can point to backup, replication, availability, or transaction issues. High used_log_space_percent is a point-in-time signal, not a full trend. Large log files affect recovery, backup, restore, and storage planning. Requires SQL Server versions that support sys.dm_db_log_stats.

5 / CPU

SQL Server CPU sizing

CPU sizing should not be based only on average utilization. Look for runnable tasks, signal waits, query shapes, parallelism behavior, and peak-window pressure. Adding cores may help, but it can also hide poor query shape or make licensing more expensive without fixing the cause.

Shows runnable tasks, worker counts, queued work, and scheduler load for visible online schedulers.

SQL

Scheduler pressure snapshot

T-SQL · 11 lines

SELECT    scheduler_id,    current_tasks_count,    runnable_tasks_count,    current_workers_count,    active_workers_count,    work_queue_count,    load_factorFROM sys.dm_os_schedulersWHERE status = N'VISIBLE ONLINE'ORDER BY runnable_tasks_count DESC, work_queue_count DESC, scheduler_id;
Review before runningT-SQLUTF-811 lines

runnable_tasks_count points to work waiting for CPU at the sample moment. work_queue_count can point to queued scheduler work. One sample is not a trend; capture during known peak windows. CPU pressure should be compared with waits, top queries, and job timing.

Shows accumulated wait patterns since the last SQL Server restart, excluding common idle waits.

SQL

Wait stats snapshot

T-SQL · 23 lines

SELECT TOP (40)    wait_type,    waiting_tasks_count,    wait_time_ms,    signal_wait_time_ms,    CONVERT(decimal(9,2), wait_time_ms / 1000.0) AS wait_time_seconds,    CONVERT(decimal(9,2), signal_wait_time_ms / 1000.0) AS signal_wait_secondsFROM sys.dm_os_wait_statsWHERE wait_type NOT LIKE N'SLEEP%'  AND wait_type NOT IN (      N'BROKER_TASK_STOP',      N'BROKER_TO_FLUSH',      N'CHECKPOINT_QUEUE',      N'CLR_AUTO_EVENT',      N'CLR_MANUAL_EVENT',      N'LAZYWRITER_SLEEP',      N'LOGMGR_QUEUE',      N'REQUEST_FOR_DEADLOCK_SEARCH',      N'SQLTRACE_BUFFER_FLUSH',      N'XE_DISPATCHER_WAIT',      N'XE_TIMER_EVENT'  )ORDER BY wait_time_ms DESC;
Review before runningT-SQLUTF-823 lines

High signal waits can support a CPU-pressure story. Wait stats are cumulative since startup; uptime changes the meaning. Do not treat one wait type as a diagnosis by itself. Capture before and after peak periods when possible.

6 / Memory

SQL Server memory sizing

Memory fit is not proven by one counter. Review the configured memory ceiling, memory clerks, grants, waiting grants, cache behavior, file reads, and the queries asking for large grants. A workload can have enough total RAM and still suffer because one report, ETL step, or bad estimate asks for too much at the wrong time.

Shows where SQL Server memory is currently allocated by clerk.

SQL

Top memory clerks

T-SQL · 8 lines

SELECT TOP (30)    type,    name,    CONVERT(decimal(18,2), pages_kb / 1024.0) AS pages_mb,    CONVERT(decimal(18,2), virtual_memory_committed_kb / 1024.0) AS virtual_committed_mb,    CONVERT(decimal(18,2), awe_allocated_kb / 1024.0) AS awe_allocated_mbFROM sys.dm_os_memory_clerksORDER BY pages_kb DESC;
Review before runningT-SQLUTF-88 lines

Memory clerks show allocation shape, not a complete health verdict. Large clerks should be interpreted with workload, uptime, and configuration. Compare with storage reads and grants before deciding memory is the bottleneck. Some memory use is normal and beneficial cache behavior.

Summarizes active query memory grants and shows the largest current grant requests.

SQL

Memory grants and waiting grants

T-SQL · 26 lines

SELECT    SYSDATETIME() AS sample_time,    COUNT(*) AS active_grants,    SUM(CASE WHEN mg.grant_time IS NULL THEN 1 ELSE 0 END) AS waiting_grants,    CONVERT(decimal(18,2), SUM(mg.requested_memory_kb) / 1024.0) AS requested_memory_mb,    CONVERT(decimal(18,2), SUM(mg.granted_memory_kb) / 1024.0) AS granted_memory_mb,    CONVERT(decimal(18,2), SUM(mg.used_memory_kb) / 1024.0) AS used_memory_mbFROM sys.dm_exec_query_memory_grants AS mg; SELECT TOP (25)    mg.session_id,    mg.requested_memory_kb / 1024 AS requested_memory_mb,    mg.granted_memory_kb / 1024 AS granted_memory_mb,    mg.used_memory_kb / 1024 AS used_memory_mb,    mg.wait_time_ms,    mg.dop,    SUBSTRING(        st.text,        (er.statement_start_offset / 2) + 1,        ((CASE er.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE er.statement_end_offset END - er.statement_start_offset) / 2) + 1    ) AS running_statementFROM sys.dm_exec_query_memory_grants AS mgLEFT JOIN sys.dm_exec_requests AS er    ON er.session_id = mg.session_idOUTER APPLY sys.dm_exec_sql_text(er.sql_handle) AS stORDER BY mg.requested_memory_kb DESC;
Review before runningT-SQLUTF-826 lines

waiting_grants can point to RESOURCE_SEMAPHORE-style pressure. Large grants often need query-plan and estimate review, not only more RAM. Run this during slow periods or known reporting windows. No rows in the detail query means no active grants at that moment.

Database-scoped Query Store query for recent CPU, logical reads, and memory-heavy query patterns.

SQL

Query Store top resource queries

T-SQL · 19 lines

SELECT TOP (25)    DB_NAME() AS database_name,    qt.query_sql_text,    SUM(rs.count_executions) AS executions,    CONVERT(decimal(18,2), SUM(rs.avg_cpu_time * rs.count_executions) / 1000.0) AS total_cpu_ms,    CONVERT(decimal(18,2), SUM(rs.avg_logical_io_reads * rs.count_executions)) AS total_logical_reads,    CONVERT(decimal(18,2), SUM(rs.avg_query_max_used_memory * rs.count_executions) / 128.0) AS total_memory_pages_mbFROM sys.query_store_runtime_stats AS rsJOIN sys.query_store_plan AS p    ON p.plan_id = rs.plan_idJOIN sys.query_store_query AS q    ON q.query_id = p.query_idJOIN sys.query_store_query_text AS qt    ON qt.query_text_id = q.query_text_idJOIN sys.query_store_runtime_stats_interval AS rsi    ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_idWHERE rsi.start_time >= DATEADD(day, -7, SYSUTCDATETIME())GROUP BY qt.query_sql_textORDER BY total_cpu_ms DESC;
Review before runningT-SQLUTF-819 lines

Run this inside a user database with Query Store enabled. The time window is the last seven days in Query Store runtime stats. High CPU, reads, or memory signals should lead to plan review. If Query Store is off, use monitoring data or cached-plan analysis instead.

7 / Storage

SQL Server storage sizing and I/O latency

Storage sizing has at least three separate questions: enough room, enough throughput, and acceptable latency. A server can have free disk space and still be undersized because writes stall, reads wait, backups overrun, or tempdb shares a path with other busy files.

Uses sys.dm_io_virtual_file_stats to show read, write, and combined latency per database file.

SQL

File I/O latency

T-SQL · 17 lines

SELECT    DB_NAME(vfs.database_id) AS database_name,    mf.type_desc,    mf.name AS logical_name,    mf.physical_name,    vfs.num_of_reads,    vfs.num_of_writes,    CONVERT(decimal(18,2), vfs.num_of_bytes_read / 1048576.0) AS read_mb,    CONVERT(decimal(18,2), vfs.num_of_bytes_written / 1048576.0) AS written_mb,    CONVERT(decimal(18,2), vfs.io_stall_read_ms / NULLIF(vfs.num_of_reads, 0)) AS avg_read_latency_ms,    CONVERT(decimal(18,2), vfs.io_stall_write_ms / NULLIF(vfs.num_of_writes, 0)) AS avg_write_latency_ms,    CONVERT(decimal(18,2), vfs.io_stall / NULLIF(vfs.num_of_reads + vfs.num_of_writes, 0)) AS avg_total_latency_msFROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfsJOIN sys.master_files AS mf    ON mf.database_id = vfs.database_id   AND mf.file_id = vfs.file_idORDER BY avg_total_latency_ms DESC;
Review before runningT-SQLUTF-817 lines

Latency is cumulative since database open or instance start. Separate data, log, and tempdb behavior before blaming one storage tier. High latency during maintenance may mean a scheduling problem rather than constant undersizing. Compare with job timing, backup timing, and wait stats.

Symptom areaWhat it can look likeSizing response
CPUHigh runnable tasks, SOS scheduler waits, plan regressions, parallelism pressure.Check workload shape and top queries before adding cores.
MemoryGrants pending, RESOURCE_SEMAPHORE, heavy clerks, repeated reads from storage.Check memory settings, grants, cache fit, and query shape together.
StorageHigh file latency, backup windows drifting, CHECKDB or maintenance overruns.Separate data, log, tempdb, and backup paths where possible.
TempdbVersion store growth, internal object growth, PAGELATCH waits, spill-heavy requests.Use the tempdb guide before changing file count or moving storage.
ConcurrencyBlocking, worker pressure, peak-only slowdowns, job/user overlap.Review scheduling, transaction scope, and workload overlap before hardware.

8 / Tempdb and concurrency

SQL Server tempdb sizing and concurrency pressure

Tempdb pressure is capacity, workload, and concurrency at the same time. It can come from user objects, internal worktables, version store, spills, row-versioning isolation, maintenance, reporting, or overlapping jobs. Use the checks here to decide whether tempdb is part of the sizing answer or a symptom of query and workload shape.

Lists tempdb file size, growth setting, max size, and storage path.

SQL

Tempdb file layout

T-SQL · 18 lines

SELECT    df.file_id,    df.name AS logical_name,    df.type_desc,    df.physical_name,    CONVERT(decimal(18,2), df.size / 128.0) AS size_mb,    CASE        WHEN df.is_percent_growth = 1            THEN CONCAT(df.growth, N'%')        ELSE CONCAT(CONVERT(decimal(18,2), df.growth / 128.0), N' MB')    END AS growth_setting,    CASE        WHEN df.max_size = -1 THEN N'Unlimited'        WHEN df.max_size = 0 THEN N'No growth'        ELSE CONCAT(CONVERT(decimal(18,2), df.max_size / 128.0), N' MB')    END AS max_sizeFROM tempdb.sys.database_files AS dfORDER BY df.type_desc, df.file_id;
Review before runningT-SQLUTF-818 lines

File layout matters, but file count should not be changed from a generic rule alone. Growth settings should be predictable enough not to join the incident. Physical paths show whether tempdb has the intended storage. Some tempdb changes require restart and rollback planning.

Splits tempdb space into free space, user objects, internal objects, version store, and mixed extents.

SQL

Current tempdb space usage

T-SQL · 15 lines

USE tempdb; SELECT    df.file_id,    df.name AS file_name,    CONVERT(decimal(18,2), fs.total_page_count / 128.0) AS total_mb,    CONVERT(decimal(18,2), fs.unallocated_extent_page_count / 128.0) AS free_mb,    CONVERT(decimal(18,2), fs.user_object_reserved_page_count / 128.0) AS user_objects_mb,    CONVERT(decimal(18,2), fs.internal_object_reserved_page_count / 128.0) AS internal_objects_mb,    CONVERT(decimal(18,2), fs.version_store_reserved_page_count / 128.0) AS version_store_mb,    CONVERT(decimal(18,2), fs.mixed_extent_page_count / 128.0) AS mixed_extents_mbFROM sys.dm_db_file_space_usage AS fsJOIN sys.database_files AS df    ON df.file_id = fs.file_idORDER BY df.file_id;
Review before runningT-SQLUTF-815 lines

user_objects_mb points toward temp tables and explicit tempdb objects. internal_objects_mb often points toward worktables, sorts, hashes, and spills. version_store_mb matters when row-versioning or long transactions are involved. Free space alone does not prove tempdb health.

Shows current requests with waits, blockers, CPU, reads, writes, and running statement text.

SQL

Active requests, waits, and blocking

T-SQL · 23 lines

SELECT    r.session_id,    r.status,    r.command,    r.cpu_time,    r.total_elapsed_time,    r.wait_type,    r.wait_time,    r.wait_resource,    r.blocking_session_id,    r.reads,    r.writes,    r.logical_reads,    DB_NAME(r.database_id) AS database_name,    SUBSTRING(        st.text,        (r.statement_start_offset / 2) + 1,        ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE r.statement_end_offset END - r.statement_start_offset) / 2) + 1    ) AS running_statementFROM sys.dm_exec_requests AS rOUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS stWHERE r.session_id <> @@SPIDORDER BY r.total_elapsed_time DESC;
Review before runningT-SQLUTF-823 lines

Use this during the slow window, not hours later. blocking_session_id connects capacity symptoms to lock chains. Logical reads and writes help connect query shape to capacity pressure. For deeper lock chains, continue with the blocking guide.

9 / Operational load

SQL Server sizing for jobs, backups, and HA

User workload is not the whole workload. Backups, CHECKDB, index maintenance, ETL, reporting, Availability Group synchronization, failover behavior, and monitoring can all change the sizing answer. If these jobs are ignored, the server can look correctly sized until the first real maintenance window.

Shows recent job step duration and status so operational workload can be included in sizing.

SQL

Recent SQL Agent job timing

T-SQL · 16 lines

SELECT TOP (120)    j.name AS job_name,    h.step_id,    h.step_name,    h.run_status,    msdb.dbo.agent_datetime(h.run_date, h.run_time) AS run_start_time,    ((h.run_duration / 10000) * 3600)      + (((h.run_duration % 10000) / 100) * 60)      + (h.run_duration % 100) AS duration_seconds,    h.messageFROM msdb.dbo.sysjobhistory AS hJOIN msdb.dbo.sysjobs AS j    ON j.job_id = h.job_idWHERE h.run_date >= CONVERT(int, CONVERT(char(8), DATEADD(day, -14, GETDATE()), 112))  AND h.step_id > 0ORDER BY run_start_time DESC, duration_seconds DESC;
Review before runningT-SQLUTF-816 lines

Long-running jobs can explain peak pressure and maintenance windows. Failed or retried steps can hide real capacity or scheduling problems. Compare run_start_time with monitoring, waits, and file latency. The query reads msdb job history only.

Shows recent backup duration, size, compressed size, and destination.

SQL

Backup duration and size

T-SQL · 14 lines

SELECT TOP (100)    bs.database_name,    bs.type AS backup_type,    bs.backup_start_date,    bs.backup_finish_date,    DATEDIFF(second, bs.backup_start_date, bs.backup_finish_date) AS duration_seconds,    CONVERT(decimal(18,2), bs.backup_size / 1048576.0) AS backup_size_mb,    CONVERT(decimal(18,2), bs.compressed_backup_size / 1048576.0) AS compressed_backup_size_mb,    bmf.physical_device_nameFROM msdb.dbo.backupset AS bsLEFT JOIN msdb.dbo.backupmediafamily AS bmf    ON bmf.media_set_id = bs.media_set_idWHERE bs.backup_start_date >= DATEADD(day, -30, GETDATE())ORDER BY bs.backup_start_date DESC;
Review before runningT-SQLUTF-814 lines

Backup duration affects maintenance windows and storage throughput needs. Large compressed_backup_size changes restore and offload planning. Physical device paths can reveal shared storage or network bottlenecks. A backup that exists is not the same as a tested restore.

HA note

Availability Groups, failover clustering, log shipping, replication, and recovery targets can all change CPU, storage, network, licensing, and maintenance requirements. If HA design is still open, use the SQL Server failover guide for the technical design and the passive node licensing guide for the second-node licensing boundary.

10 / Platform constraints

SQL Server capacity planning for growth and virtualization

Growth planning should name which thing is growing: data footprint, transaction volume, reporting load, user concurrency, retention, job duration, backup size, or HA complexity. Those do not grow at the same rate, and they do not put pressure on the same resource.

Virtualization and licensing should be treated as design constraints, not footnotes. Assigned CPU is not always dependable CPU. A smaller licensing footprint can be sensible, but not if it leaves the workload permanently constrained. Treat licensing notes here as technical planning inputs, not legal advice.

Platform shapeUseful whenSizing caution
PhysicalCleaner ownership of CPU, memory, and storage behavior.Can still be wrong if storage, growth, HA, or licensing are guessed.
VirtualFlexible placement and easier resizing in some shops.Assigned resources are not the same as dependable resources under host load.
Cloud or managedElastic options and managed platform features.Sizing depends on tier limits, storage latency model, IO caps, and cost behavior.
Consolidated estateCan reduce operational sprawl.One busy workload can distort the sizing story for every neighbor.

11 / Decision output

Turn checks into a SQL Server sizing decision

The final output should be short enough to use. List the current bottleneck, the headroom needed, the checks that support the conclusion, the weak inputs, the near-term change, and when the sizing should be reviewed again.

Output itemWhat to write down
Current bottleneckName the main limiting resource and the checks that support it.
Required headroomState the buffer for peak workload, maintenance, backups, and growth.
Risky inputsList missing baselines, short uptime, untested failover, weak job history, or unknown growth.
Near-term changeRecommend the smallest useful platform, workload, or operational change.
Next review dateSet a review trigger based on time, growth, migration, upgrade, or repeated incidents.

What not to change blindly

1

Do not buy more CPU before checking scheduler pressure, top queries, and licensing impact.

2

Do not raise memory without checking grants, clerks, OS needs, and query shape.

3

Do not move storage from a single latency sample without checking job and backup timing.

4

Do not change tempdb file count or paths without restart and rollback planning.

5

Do not size from a quiet week when month-end or batch peaks are the real workload.

When review helps

Ask for a sizing review before procurement, consolidation, migration target selection, HA design, a large growth period, or a repeated performance problem that might be workload shape rather than hardware.

Send instance output, file inventory, waits, file latency, tempdb output, job timing, backup history, monitoring data, and the business event that is forcing the capacity decision.

Next step

If the capacity question needs a workload-based answer instead of a hardware guess, use SQL Server consulting or the SQL Server health audit page.

Next useful reads: the SQL Server monitoring guide for baseline capture, the SQL Server indexing guide for query-shape pressure, the SQL Server tempdb guide for tempdb pressure, and the SQL Server performance review page when slow queries and capacity are mixed together.