Table of contents

SQL Server performance problems are not always caused by complicated queries or undersized hardware. Some of the most disruptive issues come from basic configuration items that were never reviewed after the server was installed, virtualized, upgraded, or assigned additional applications. A single overlooked setting can create memory pressure, excessive disk activity, unstable performance, or unnecessary competition between SQL Server and Windows.

This guide provides a practical starting point for IT professionals who manage a SQL Server but are not full-time database administrators. It focuses on safe inspections, common configuration mistakes, and the questions that should be answered before making changes. The goal is not to tune every query. The goal is to identify the simple, frequently missed items that can make an outsized difference.

Important: Most inspection queries in this article are read-only. Configuration changes should still be documented, approved, tested, and completed during an appropriate maintenance window. Confirm application-vendor requirements before changing settings on a server supporting specialized software.

Begin With the Entire Server, Not Just SQL Server #

SQL Server does not operate in isolation.

Before changing SQL settings, determine what else is running on the machine:

  • Application servers
  • Reporting services
  • Web services
  • Document-management systems
  • Backup software
  • Security agents
  • Monitoring tools
  • Integration services
  • Data gateways
  • Other database engines

A memory setting that is reasonable for a dedicated SQL Server may be completely inappropriate for a server running several business applications.

The first questions should be:

  1. How much physical memory is installed?
  2. How much memory does SQL Server currently use?
  3. What other processes consume significant memory?
  4. Is the system experiencing Windows memory pressure?
  5. Is storage latency increasing when the problem occurs?
  6. Does performance gradually decline until the server is restarted?

A reboot may temporarily improve performance because it clears caches, releases leaked or retained memory, restarts application workers, and resets accumulated workload. That does not identify the underlying cause. It only resets the environment.

1. Check the SQL Server Memory Limit #

SQL Server intentionally uses available memory to cache database pages and query plans. High SQL Server memory use is therefore not automatically a memory leak. However, SQL Server still needs an appropriate maximum memory limit so Windows and other applications retain enough memory to operate. A limit that is too high can create operating-system memory pressure. A limit that is too low can reduce SQL Server’s cache efficiency and increase physical database reads. Microsoft recommends sizing the limit only after accounting for Windows, other applications, other SQL instances, thread stacks, and allocations that may exist outside the primary SQL memory limit.

Check the configured and active limits #

Run this read-only query in SQL Server Management Studio:

SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value,
    description
FROM sys.configurations
WHERE name IN
(
    'min server memory (MB)',
    'max server memory (MB)'
)
ORDER BY name;

What the columns mean #

Configured value is what SQL Server has been told to use. Running value is what the SQL Server instance is currently using as its configuration. The default maximum value of 2147483647 MB effectively means that no practical SQL-specific cap has been established. That does not mean SQL Server instantly consumes all memory, but it allows the engine to grow as workload demands and system conditions permit.

Do not apply a universal percentage #

Rules such as “give SQL 80% of the server” are only rough starting points. They can be misleading on shared application servers.

A better model is:

Total physical memory
minus Windows requirements
minus other applications and services
minus other SQL Server instances
minus SQL allocations outside the primary memory limit
equals the initial SQL Server maximum

Then monitor the complete server through a normal business cycle before adjusting further.

Database size is not the same as memory requirement #

A one-terabyte database does not require one terabyte of RAM. SQL Server uses memory as a cache for active data pages, execution plans, memory grants, locks, and other internal structures. The working set and workload are usually more important than total database size. A very large but rarely accessed database may have little effect on memory. A much smaller database supporting heavy reporting, complex searches, or frequent transactions may demand far more memory.

2. Understand What the Memory Limit Does Not Include #

The max server memory setting controls much of SQL Server’s managed memory, including the buffer pool, caches, query execution memory, the lock manager, and many internal memory clerks. It does not necessarily represent the absolute maximum size of the entire sqlservr.exe process. Thread stacks, certain direct Windows allocations, linked-server components, backup buffers, external DLLs, and other components may consume memory outside the configured value. SQL Server process memory can therefore exceed the value shown under max server memory. This is one reason the SQL limit should not be set equal to all memory not currently used by Windows.

View SQL Server process memory #

SELECT
    physical_memory_in_use_kb / 1024 AS sql_physical_memory_in_use_mb,
    locked_page_allocations_kb / 1024 AS locked_pages_mb,
    virtual_address_space_committed_kb / 1024 AS committed_virtual_memory_mb,
    process_physical_memory_low,
    process_virtual_memory_low
FROM sys.dm_os_process_memory;

What to look for #

  • process_physical_memory_low = 1 indicates that SQL Server has detected low physical memory.
  • process_virtual_memory_low = 1 indicates low virtual address-space conditions.
  • locked_pages_mb helps show whether SQL Server has allocations locked in physical memory.

A single snapshot is not enough. Capture this information when the server is healthy and again while users are experiencing poor performance.

3. Check Windows Memory Before Blaming SQL Server #

A server can show high page-fault activity without experiencing harmful disk paging. This distinction is frequently misunderstood.

Page faults are not automatically bad #

A page fault occurs when a process requests a memory page that is not currently mapped into its working set.

That fault may be:

Soft: Windows resolves the request from physical memory or another in-memory location.

Hard: Windows must retrieve the page from disk-backed storage, such as the pagefile or a mapped file.

Windows Performance Monitor’s Memory\Page Faults/sec counter includes more than just hard faults. A high value does not, by itself, prove that the server is thrashing its pagefile.

For real disk-backed paging, inspect:

  • Resource Monitor’s Hard Faults/sec
  • Memory\Pages Input/sec
  • Memory\Page Reads/sec
  • Available physical memory
  • Pagefile activity
  • Disk latency on the volume holding the pagefile

Do not treat an arbitrary number such as 20, 50, or 1,000 page faults per second as a universal failure threshold. The type of fault and its effect on storage matter more than the raw count.

Check Windows memory through SQL Server #

SELECT
    total_physical_memory_kb / 1024 AS total_physical_memory_mb,
    available_physical_memory_kb / 1024 AS available_physical_memory_mb,
    total_page_file_kb / 1024 AS total_page_file_mb,
    available_page_file_kb / 1024 AS available_page_file_mb,
    system_memory_state_desc
FROM sys.dm_os_sys_memory;

This query is read-only. The system_memory_state_desc value provides SQL Server’s view of the Windows memory condition.

4. Use Lock Pages in Memory Carefully #

Lock Pages in Memory, commonly called LPIM, allows eligible SQL Server memory allocations to remain in physical RAM rather than being paged out by Windows. It can help when Windows is trimming SQL Server’s working set. Evidence may include sudden drops in SQL Server memory or SQL Server error 17890 indicating that a significant portion of process memory was paged out. Microsoft does not recommend enabling LPIM automatically on every SQL Server without evidence of a paging problem.

LPIM does not solve insufficient memory #

LPIM protects eligible SQL Server memory. It does not create additional RAM. If SQL Server is allowed to lock too much memory, Windows and other applications may have less memory available to recover from pressure. Microsoft strongly recommends pairing LPIM with an explicit, carefully sized maximum SQL Server memory setting.

Check the SQL memory model #

SELECT
    sql_memory_model_desc
FROM sys.dm_os_sys_info;

Common results include:

  • CONVENTIONAL
  • LOCK_PAGES
  • LARGE_PAGES

LOCK_PAGES indicates that SQL Server is using locked-page allocations.

Verify the SQL Server service account #

The LPIM right must be granted to the account running the SQL Server Database Engine service.

Use SQL Server Configuration Manager or Windows Services to identify the account. For a default instance using a virtual service account, it may resemble: NT SERVICE\MSSQLSERVER

A named instance may use an account resembling: NT SERVICE\MSSQL$InstanceName

When adding a local virtual service account through Windows policy, ensure the object picker is searching the local computer rather than only the Active Directory domain. A SQL Server service restart is required before the service receives the new right.

5. Review the Windows Pagefile #

The Windows pagefile is a safety mechanism. It is not a substitute for adequate physical memory.A pagefile that is extremely small may prevent Windows from handling temporary commitment spikes or collecting useful crash-dump information. A pagefile that is heavily used during normal operations indicates that the server’s memory design should be investigated. There is no single pagefile size that is correct for every SQL Server.

The appropriate configuration depends on:

  • Windows crash-dump requirements
  • Total committed memory
  • Available disk space
  • Other applications
  • Server role
  • Organizational standards
  • Microsoft and application-vendor guidance

For many general-purpose servers, a system-managed pagefile on the operating-system volume is a practical default. Organizations with specific crash-dump, storage, or performance requirements may deliberately use a fixed or custom size.

What not to do #

Do not place the pagefile on a busy SQL data volume merely because it has more free space. Pagefile activity could compete with database I/O. Do not disable the pagefile without confirming the consequences for crash dumps and total system commit. Do not assume that increasing the pagefile will solve a physical-memory shortage. It may prevent a failure while making performance significantly slower.

6. Check Whether SQL Server Has Enough CPU Without Overusing It #

CPU utilization alone does not tell you whether SQL Server is properly configured. A server can have moderate overall CPU use while one query monopolizes several logical processors. It can also show low CPU use while waiting on slow storage, locks, or memory grants.

Three server-level settings deserve review:

  • Maximum Degree of Parallelism
  • Cost Threshold for Parallelism
  • Priority Boost

Maximum Degree of Parallelism #

Maximum Degree of Parallelism, or MAXDOP, limits how many processors a parallel query plan may use for an individual parallel operation.

Check it with:

SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value
FROM sys.configurations
WHERE name = 'max degree of parallelism';

A value of:

  • 0 allows SQL Server to use all available logical processors
  • 1 disables parallel plans
  • A higher value limits parallelism to that degree

MAXDOP should be selected using the SQL Server version, CPU count, NUMA arrangement, workload, and application-vendor guidance. Microsoft warns that values above eight often create unwanted resource consumption, although the correct value remains environment-specific. For a modest virtual server with eight logical processors, a value such as four may be a reasonable starting point, but it should not be treated as a universal standard.

Cost Threshold for Parallelism #

This setting determines when SQL Server begins considering a parallel execution plan.

Check it with:

SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value
FROM sys.configurations
WHERE name = 'cost threshold for parallelism';

The default value is 5, but Microsoft describes that value as a starting point rather than a modern best-practice recommendation. Raising it can prevent small queries from using parallel plans unnecessarily. Microsoft recommends making incremental adjustments and observing a full business cycle before changing it again. A commonly tested starting value is 50, but the correct value must be validated against the actual workload. Do not change MAXDOP and cost threshold repeatedly without establishing a baseline. Otherwise, it becomes difficult to know which change helped or hurt.

Priority Boost #

The priority boost setting causes SQL Server to run at a higher Windows scheduling priority.

Check it with:

SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value
FROM sys.configurations
WHERE name = 'priority boost';

For normal SQL Server operation, this should generally be 0. Microsoft states that Priority Boost is unnecessary for normal performance tuning, can interfere with smooth server operation, may deprive Windows and network functions of resources, and is planned for removal from a future SQL Server version. It should only be used in exceptional circumstances under appropriate expert guidance. This is a classic example of a setting that sounds beneficial but can make a shared server less stable.

7. Check Optimize for Ad Hoc Workloads #

SQL Server stores execution plans in memory. If an application creates many one-time, non-parameterized queries, the plan cache can fill with plans that are never reused. Optimize for ad hoc workloads changes the first cache entry for an ad hoc query into a small plan stub. SQL Server stores the complete plan if the query is executed again.

Check the setting:

SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value
FROM sys.configurations
WHERE name = 'optimize for ad hoc workloads';

Check for large numbers of one-use plans #

SELECT
    objtype,
    cacheobjtype,
    COUNT_BIG(*) AS plan_count,
    SUM(CAST(size_in_bytes AS BIGINT)) / 1024.0 / 1024.0 AS cache_size_mb
FROM sys.dm_exec_cached_plans
GROUP BY
    objtype,
    cacheobjtype
ORDER BY
    cache_size_mb DESC;

A more focused view:

SELECT
    COUNT_BIG(*) AS single_use_plan_count,
    SUM(CAST(size_in_bytes AS BIGINT)) / 1024.0 / 1024.0
        AS single_use_plan_cache_mb
FROM sys.dm_exec_cached_plans
WHERE usecounts = 1
  AND objtype = 'Adhoc';

Enabling the option can improve plan-cache efficiency when single-use ad hoc plans consume meaningful memory. It is not automatically beneficial for every workload. Microsoft notes that environments where ad hoc queries are repeatedly reused may incur additional optimization work. The permanent correction may be application parameterization rather than a server setting.

8. Inventory Database Sizes Correctly #

Allocated file size is not the same as active data size. A database file may be preallocated to reduce repeated growth events. A 200 GB data file does not necessarily contain 200 GB of active table and index data.

Show allocated database and log-file sizes #

SELECT
    DB_NAME(database_id) AS database_name,
    CAST(
        SUM(CASE WHEN type = 0 THEN size ELSE 0 END)
        * 8.0 / 1024
        AS DECIMAL(18, 2)
    ) AS data_file_size_mb,
    CAST(
        SUM(CASE WHEN type = 1 THEN size ELSE 0 END)
        * 8.0 / 1024
        AS DECIMAL(18, 2)
    ) AS log_file_size_mb,
    CAST(
        SUM(size) * 8.0 / 1024 / 1024
        AS DECIMAL(18, 2)
    ) AS total_allocated_gb
FROM sys.master_files
GROUP BY database_id
ORDER BY total_allocated_gb DESC;

This query is read-only. It reports allocated file size. It does not show how much space inside every data file is actually occupied.

Show every SQL file and its location #

SELECT
    DB_NAME(database_id) AS database_name,
    name AS logical_file_name,
    type_desc,
    physical_name,
    CAST(size * 8.0 / 1024 AS DECIMAL(18, 2)) AS allocated_size_mb,
    CASE
        WHEN max_size = -1 THEN 'Unlimited'
        ELSE CAST(max_size * 8.0 / 1024 AS VARCHAR(30)) + ' MB'
    END AS maximum_size,
    CASE
        WHEN is_percent_growth = 1
            THEN CAST(growth AS VARCHAR(20)) + '%'
        ELSE CAST(growth * 8.0 / 1024 AS VARCHAR(30)) + ' MB'
    END AS growth_setting
FROM sys.master_files
ORDER BY
    database_name,
    type_desc,
    logical_file_name;

This report helps identify:

  • Data and log files on the same volume
  • Unexpected database copies
  • Old test databases
  • Percentage-based autogrowth
  • Very small growth increments
  • Files stored on an operating-system volume
  • Files placed in obsolete directories

9. Identify Duplicate, Test, and Inactive Databases #

Old test databases and copied production databases are common. An unused database does not continuously consume memory equal to its allocated disk size. However, it still creates governance, security, backup, storage, patching, and recovery obligations.

It may also affect performance indirectly if:

  • Backup jobs include it
  • Integrity checks scan it
  • Index-maintenance jobs process it
  • Monitoring tools query it
  • Reporting tools connect to it
  • Applications still reference it
  • Antivirus or backup tools scan its files
  • Administrators mistake it for the production database

Review recent index activity #

SELECT
    d.name AS database_name,
    MAX(
        (
            SELECT MAX(last_access)
            FROM
            (
                VALUES
                    (ius.last_user_seek),
                    (ius.last_user_scan),
                    (ius.last_user_lookup),
                    (ius.last_user_update)
            ) AS access_dates(last_access)
        )
    ) AS last_observed_user_activity
FROM sys.databases AS d
LEFT JOIN sys.dm_db_index_usage_stats AS ius
    ON d.database_id = ius.database_id
GROUP BY d.name
ORDER BY last_observed_user_activity;

Important limitation #

This information resets after events such as:

  • SQL Server restart
  • Database detach or attach
  • Database shutdown
  • Some upgrades or maintenance activity

An empty date does not prove that a database is unused.

Before taking a database offline or deleting it:

  1. Identify its business owner.
  2. Check application connection strings.
  3. Review SQL Agent jobs.
  4. Review reporting and integration tools.
  5. Confirm backups.
  6. Document the decision.
  7. Test a restore.
  8. Take it offline before deleting it.
  9. Observe for an agreed period.
  10. Retain the backup according to policy.

Deleting old databases is not a query-optimization technique. It is good technology bookkeeping and risk reduction.

10. Review Data, Log, Backup, and TempDB Locations #

Separating SQL files onto different drive letters does not automatically improve performance. The underlying storage matters. Two virtual disks may still reside on the same physical storage pool, controller, SAN tier, or RAID group. In that case, separate drive letters provide organization and management boundaries but may not provide true I/O isolation.

Typical architecture #

A well-organized SQL Server may use:

C:  Windows and application binaries
D:  SQL data files
L:  SQL transaction logs
T:  TempDB
B:  SQL backups

The exact letters do not matter.

The important questions are:

  • Are the workloads truly separated at the storage layer?
  • Does each volume have appropriate performance and redundancy?
  • Can a runaway file fill the operating-system volume?
  • Are backups isolated from active database I/O?
  • Are data, logs, and TempDB protected and monitored appropriately?

Data versus log workloads #

Database data files often experience mixed or random I/O. Transaction logs are primarily written sequentially, though recovery and backup operations also read them. Separating them can improve performance, recovery management, and capacity control when the underlying storage is also meaningfully separated. It is not an absolute requirement for every small environment. Do not move SQL files solely because a checklist says to use another drive. Measure the storage behavior first.


11. Inspect TempDB #

TempDB supports internal work tables, sorting, hashing, row versioning, temporary objects, index operations, and query spills. A poorly configured TempDB can create performance problems even when the production databases are healthy.

Show TempDB file configuration #

USE tempdb;
GO

SELECT
    name,
    type_desc,
    physical_name,
    CAST(size * 8.0 / 1024 AS DECIMAL(18, 2)) AS size_mb,
    CASE
        WHEN is_percent_growth = 1
            THEN CAST(growth AS VARCHAR(20)) + '%'
        ELSE CAST(growth * 8.0 / 1024 AS VARCHAR(30)) + ' MB'
    END AS growth_setting,
    CASE
        WHEN max_size = -1 THEN 'Unlimited'
        ELSE CAST(max_size * 8.0 / 1024 AS VARCHAR(30)) + ' MB'
    END AS maximum_size
FROM sys.database_files
ORDER BY type_desc, name;

Basic items to verify #

  • TempDB is not left at a tiny default size.
  • Autogrowth is a reasonable fixed number of megabytes.
  • TempDB has adequate free disk space.
  • Multiple TempDB data files are equally sized.
  • Equal data files use matching growth settings.
  • The number of files is appropriate for the workload and CPU layout.
  • TempDB is placed on suitable storage.

Microsoft recommends multiple equally sized TempDB data files when contention warrants them. Modern SQL Server setup commonly recommends multiple files based on logical processor count, up to eight as an initial configuration. More files are not automatically better and should be justified by observed contention. Do not repeatedly shrink TempDB as routine maintenance. Correct the sizing and workload issue instead.

12. Measure Storage Latency, Not Just Queue Length #

Disk Active Time and queue length can be useful, but neither should be interpreted alone. A storage volume may show high Active Time while still completing requests quickly. Modern storage arrays and virtualized storage systems can process many operations concurrently. A queue length that looks high on a single spinning disk may be acceptable on a high-performance array. There is no reliable universal rule that every disk queue must remain below 2.

Focus on:

  • Read latency
  • Write latency
  • Throughput
  • IOPS
  • Queue behavior
  • SQL wait types
  • The storage platform’s own telemetry
  • Changes during user-reported slowdowns

Microsoft identifies these Windows counters for storage latency:

PhysicalDisk\Avg. Disk sec/Read
PhysicalDisk\Avg. Disk sec/Write
PhysicalDisk\Avg. Disk sec/Transfer

Microsoft notes that SQL Server disk transfers are typically below approximately 15 milliseconds, but acceptable latency still depends on the storage design and workload. Sustained latency and business impact matter more than a single spike.

Measure SQL file latency #

SELECT
    DB_NAME(vfs.database_id) AS database_name,
    mf.type_desc,
    mf.physical_name,
    vfs.num_of_reads,
    CASE
        WHEN vfs.num_of_reads = 0 THEN 0
        ELSE CAST(
            vfs.io_stall_read_ms * 1.0 / vfs.num_of_reads
            AS DECIMAL(18, 2)
        )
    END AS average_read_latency_ms,
    vfs.num_of_writes,
    CASE
        WHEN vfs.num_of_writes = 0 THEN 0
        ELSE CAST(
            vfs.io_stall_write_ms * 1.0 / vfs.num_of_writes
            AS DECIMAL(18, 2)
        )
    END AS average_write_latency_ms
FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs
INNER JOIN sys.master_files AS mf
    ON vfs.database_id = mf.database_id
   AND vfs.file_id = mf.file_id
ORDER BY
    average_read_latency_ms DESC,
    average_write_latency_ms DESC;

Important limitation #

These values are cumulative since the SQL Server service started or since the underlying statistics were reset. Compare them over time and capture them during known performance events.

13. Review Transaction Log Use #

A large transaction log is not automatically a problem. The log may have been sized intentionally to support normal operations. Repeatedly shrinking it may create a cycle in which the file shrinks and then regrows, causing fragmentation and avoidable storage activity.

Check log allocation and current use #

DBCC SQLPERF(LOGSPACE);

This command reports:

  • Database name
  • Log size
  • Percentage used
  • Status

It is informational and does not shrink or modify the log.

If a log remains mostly empty but extremely large, investigate:

  • Recovery model
  • Log backup frequency
  • Long-running transactions
  • Replication
  • Availability features
  • Delayed log truncation
  • Index-maintenance operations
  • Previous one-time growth events

Do not shrink the log until you understand why it grew and what its normal operating size should be.

14. Check Backups Before Calling the Server Healthy #

Performance tuning is not successful if it weakens recoverability.

Review:

  • Last successful full backup
  • Last differential backup
  • Last transaction-log backup
  • Recovery model
  • Backup location
  • Backup compression
  • Backup checksum
  • Restore-test history
  • Available space on the backup target

Read-only backup summary #

SELECT
    d.name AS database_name,
    d.recovery_model_desc,
    MAX(CASE WHEN bs.type = 'D' THEN bs.backup_finish_date END)
        AS last_full_backup,
    MAX(CASE WHEN bs.type = 'I' THEN bs.backup_finish_date END)
        AS last_differential_backup,
    MAX(CASE WHEN bs.type = 'L' THEN bs.backup_finish_date END)
        AS last_log_backup
FROM sys.databases AS d
LEFT JOIN msdb.dbo.backupset AS bs
    ON d.name = bs.database_name
GROUP BY
    d.name,
    d.recovery_model_desc
ORDER BY d.name;

This only reports backups recorded in the local msdb database. Third-party systems may perform backups in a way that requires additional verification. Backup compression can reduce backup size and storage I/O but may use additional CPU. Backup checksums help detect page problems during backup. Neither replaces regular restore testing.

15. Check SQL Server Version and Patch Level #

Performance symptoms may be caused or amplified by known SQL Server defects that were corrected in later cumulative updates.

Run:

SELECT
    SERVERPROPERTY('MachineName') AS machine_name,
    SERVERPROPERTY('ServerName') AS server_name,
    SERVERPROPERTY('InstanceName') AS instance_name,
    SERVERPROPERTY('Edition') AS edition,
    SERVERPROPERTY('ProductVersion') AS product_version,
    SERVERPROPERTY('ProductLevel') AS product_level,
    SERVERPROPERTY('ProductUpdateLevel') AS update_level,
    SERVERPROPERTY('ProductUpdateReference') AS update_reference;

Compare the result with:

  • Microsoft’s supported lifecycle
  • Current cumulative updates
  • Application-vendor certification
  • Operating-system compatibility
  • Backup-agent compatibility
  • High-availability requirements

Do not patch a production SQL Server without backup validation, rollback planning, application-owner approval, and an appropriate maintenance window.

16. Avoid Changing Advanced Settings Without Evidence #

SQL Server exposes many settings that sound like easy performance improvements.

Examples include:

  • Priority Boost
  • Lightweight Pooling
  • Affinity Masks
  • Lock limits
  • Query Wait
  • Network Packet Size
  • Minimum Memory Per Query
  • Index Creation Memory
  • Trace flags
  • Forced parameterization
  • Resource Governor

Most should remain at their defaults unless a qualified investigation identifies a specific need. Changing several settings at the same time creates a new problem: nobody can determine which change helped.

A disciplined process is more valuable than a list of “secret” settings:

  1. Document the symptom.
  2. Capture a baseline.
  3. Identify the likely bottleneck.
  4. Confirm vendor requirements.
  5. Change one logical group of settings.
  6. Record the previous value.
  7. Test through a normal workload.
  8. Compare results.
  9. Retain a rollback plan.

That is effective change management for database systems.

A Safe SQL Server Inspection Script #

The following script collects several basic configuration values without modifying the SQL Server.

/* ============================================================
   BASIC SQL SERVER HEALTH AND CONFIGURATION REVIEW
   Read-only inspection script
   ============================================================ */

SET NOCOUNT ON;

/* SQL Server version */
SELECT
    SERVERPROPERTY('ServerName') AS server_name,
    SERVERPROPERTY('Edition') AS edition,
    SERVERPROPERTY('ProductVersion') AS product_version,
    SERVERPROPERTY('ProductLevel') AS product_level,
    SERVERPROPERTY('ProductUpdateLevel') AS update_level;

/* Important server settings */
SELECT
    name,
    value AS configured_value,
    value_in_use AS running_value
FROM sys.configurations
WHERE name IN
(
    'min server memory (MB)',
    'max server memory (MB)',
    'max degree of parallelism',
    'cost threshold for parallelism',
    'optimize for ad hoc workloads',
    'priority boost',
    'backup compression default',
    'backup checksum default'
)
ORDER BY name;

/* SQL memory model */
SELECT
    sql_memory_model_desc
FROM sys.dm_os_sys_info;

/* Windows memory state */
SELECT
    total_physical_memory_kb / 1024 AS total_physical_memory_mb,
    available_physical_memory_kb / 1024 AS available_physical_memory_mb,
    total_page_file_kb / 1024 AS total_page_file_mb,
    available_page_file_kb / 1024 AS available_page_file_mb,
    system_memory_state_desc
FROM sys.dm_os_sys_memory;

/* SQL Server process memory */
SELECT
    physical_memory_in_use_kb / 1024 AS sql_physical_memory_in_use_mb,
    locked_page_allocations_kb / 1024 AS locked_pages_mb,
    process_physical_memory_low,
    process_virtual_memory_low
FROM sys.dm_os_process_memory;

/* Database allocation */
SELECT
    DB_NAME(database_id) AS database_name,
    CAST(
        SUM(CASE WHEN type = 0 THEN size ELSE 0 END)
        * 8.0 / 1024
        AS DECIMAL(18, 2)
    ) AS data_file_size_mb,
    CAST(
        SUM(CASE WHEN type = 1 THEN size ELSE 0 END)
        * 8.0 / 1024
        AS DECIMAL(18, 2)
    ) AS log_file_size_mb,
    CAST(
        SUM(size) * 8.0 / 1024 / 1024
        AS DECIMAL(18, 2)
    ) AS total_allocated_gb
FROM sys.master_files
GROUP BY database_id
ORDER BY total_allocated_gb DESC;

/* Database file paths and growth configuration */
SELECT
    DB_NAME(database_id) AS database_name,
    name AS logical_file_name,
    type_desc,
    physical_name,
    CAST(size * 8.0 / 1024 AS DECIMAL(18, 2)) AS allocated_size_mb,
    CASE
        WHEN is_percent_growth = 1
            THEN CAST(growth AS VARCHAR(20)) + '%'
        ELSE CAST(growth * 8.0 / 1024 AS VARCHAR(30)) + ' MB'
    END AS growth_setting
FROM sys.master_files
ORDER BY database_name, type_desc, logical_file_name;

/* Transaction-log use */
DBCC SQLPERF(LOGSPACE);

Running this script does not change SQL Server configuration, databases, files, or data. Some dynamic management views require the appropriate SQL Server permissions.

The High-Impact Items Most Often Missed #

When a SQL Server feels slow or becomes unstable over time, inspect these items first:

1. SQL Server has no reasonable memory ceiling #

SQL gradually consumes memory while Windows and other applications are left with insufficient headroom.

2. SQL Server’s memory ceiling is too restrictive #

The engine repeatedly evicts useful cache pages and performs more physical database reads than necessary.

3. The server is not dedicated to SQL #

Reporting, document management, backup tools, integrations, and other applications compete for the same CPU, memory, and storage.

4. Page faults are being interpreted incorrectly #

Total page faults, soft faults, hard faults, and pagefile activity are not interchangeable.

5. LPIM was enabled without sizing SQL memory #

SQL memory is protected, but Windows and other applications may be left with inadequate RAM.

6. Priority Boost is enabled #

SQL receives elevated scheduling priority even though Microsoft does not recommend the setting for ordinary tuning.

7. MAXDOP and parallelism threshold remain unreviewed defaults #

Small queries may use unnecessary parallelism, or large queries may monopolize CPU resources.

8. TempDB remains at installation defaults #

Tiny files and repeated autogrowth events create unnecessary overhead.

9. Data, logs, backups, and TempDB share one busy storage path #

Different workloads compete for the same underlying storage.

10. Old database copies remain inside production maintenance plans #

Backups, integrity checks, and monitoring continue processing databases nobody uses.

11. Percentage-based file growth is still enabled #

Growth events become unpredictable as databases increase in size.

12. Performance changes are made without a baseline #

Several settings are changed at once, making the outcome difficult to measure or reverse.

Frequently Asked Questions About SQL Server Memory and Hard Faults #

I still see active hard faults in Windows Resource Monitor. Is that a problem? #

Not necessarily. A hard fault occurs when Windows must retrieve a requested memory page from storage because it is not currently available in physical memory. Hard faults are a normal part of Windows memory management and do not need to remain at zero. In the example shown, the active processes are recording approximately one hard fault per second while overall physical memory usage is only 19%. By itself, that is not evidence of a memory shortage or performance problem.

The important questions are:

  • Are hard faults sustained or only occasional?
  • Do they increase significantly during periods of poor performance?
  • Is available physical memory consistently low?
  • Is pagefile activity causing measurable storage latency?
  • Does the server become slow, unresponsive, or dependent on periodic restarts?

A small number of intermittent hard faults is generally expected. Investigate further when hard faults remain elevated for extended periods and correlate with low available memory, high pagefile activity, storage latency, or user-reported slowness.

Suggested image placement: Place the Resource Monitor screenshot directly below this answer.

Suggested image caption:

Resource Monitor may show occasional hard faults even when the server has substantial available physical memory. A small real-time value does not, by itself, indicate harmful memory pressure.

What is the difference between a page fault and a hard fault? #

A page fault means that an application requested a memory page that was not immediately available in its current working set. A soft page fault can be resolved from another location in physical memory. This normally does not require storage access. A hard page fault requires Windows to retrieve the page from storage, such as the pagefile or a memory-mapped file. This distinction matters because the Windows Performance Monitor counter named Page Faults/sec includes more than just hard faults. A high total page-fault count does not automatically mean the server is paging heavily to disk.

How many hard faults per second are acceptable? #

There is no universal number that applies to every server. One hard fault per second may be harmless. A temporary spike may also be normal when an application starts, a report runs, or inactive code is loaded. The pattern and performance impact matter more than the isolated number.

Investigate when hard faults are:

  • Sustained rather than occasional
  • Increasing during business activity
  • Accompanied by very low available memory
  • Creating noticeable pagefile or disk activity
  • Correlated with high disk latency
  • Occurring while users report freezing or severe delays

A screenshot showing a value of one should not be interpreted the same way as a server sustaining hundreds or thousands of hard faults per second during poor performance.

Does low physical-memory usage prove the server is healthy? #

No. It is encouraging, but it is only one observation. Low memory usage immediately after a restart is expected because SQL Server and other applications have not yet rebuilt their caches or returned to their normal workload.

Evaluate memory after the server has operated through:

  • Normal business hours
  • Reporting workloads
  • Backup operations
  • Index maintenance
  • Document indexing
  • Scheduled application tasks
  • Several days of regular use

A useful baseline should include both healthy periods and reported slow periods.

Why is SQL Server using less memory after a restart? #

SQL Server grows its memory use as applications execute queries and frequently accessed data is loaded into cache. Immediately after a restart, SQL Server may use only a small portion of its configured maximum. This does not mean that its memory limit is being ignored. The configured maximum is a ceiling, not a reservation. SQL Server grows toward that ceiling only when the workload benefits from additional memory.

Does LOCK_PAGES mean SQL Server can no longer experience hard faults? #

No. Lock Pages in Memory protects eligible SQL Server memory allocations from ordinary Windows paging. It does not eliminate every possible page fault generated by the SQL Server process.

SQL Server can still access:

  • Executable files
  • DLLs
  • Memory-mapped files
  • Allocations outside the locked buffer pool
  • Data not currently present in its cache

Other applications on the server can also generate hard faults normally. The purpose of LPIM is to reduce harmful trimming of important SQL Server memory, not to force the server’s hard-fault counter to remain at zero.

How can I tell whether hard faults are actually hurting performance? #

Review several indicators together:

Resource Monitor
Hard Faults/sec by process
Available physical memory
Pagefile activity

Performance Monitor
Memory\Available MBytes
Memory\Pages Input/sec
Memory\Page Reads/sec
Paging File\% Usage
PhysicalDisk\Avg. Disk sec/Read
PhysicalDisk\Avg. Disk sec/Write

A concerning pattern would include sustained hard faults, falling available memory, active pagefile reads, increasing disk latency, and user-reported slowness at the same time. One isolated counter should not be used to diagnose the entire server.

Should I take action when I see one or two hard faults per second? #

Usually, no immediate action is required when the activity is brief, physical memory remains available, storage latency is healthy, and users are not experiencing performance problems. Continue monitoring through a normal workload cycle. The objective is not to eliminate every hard fault. The objective is to prevent sustained memory pressure and storage-backed paging from becoming a business-impacting bottleneck.

Why does Task Manager show SQL Server using only a few hundred megabytes? #

Task Manager may not clearly display SQL Server memory allocated through locked pages. This can make SQL Server’s visible working set look much smaller than its actual memory use. Confirm the SQL memory model and inspect sys.dm_os_process_memory. Do not rely only on Task Manager.

Does a 48 GB maximum-memory setting mean SQL Server reserves 48 GB? #

No. max server memory is primarily a ceiling. SQL Server grows toward that ceiling as workload and caching needs increase. It may use much less than the maximum after a restart or during a light workload. It is not necessary or desirable to force SQL Server to consume the entire amount simply to prove the setting works.

How quickly should SQL Server memory grow after a restart? #

There is no fixed timetable.

Growth depends on:

  • User activity
  • Reports
  • Searches
  • Indexing
  • Scheduled jobs
  • Backup operations
  • Query patterns
  • The amount of frequently accessed data
  • SQL Server’s internal memory needs

The cache may grow rapidly during a busy period or remain relatively small for days during light use.

Should I run a large query just to make SQL Server memory increase? #

No. Do not run broad counts, scans, or large searches against a production database simply to make a memory number rise. That can create unnecessary CPU, storage, locking, and cache activity. Allow the normal workload to build the cache. Use SQL Server’s own memory views to verify operation.

Why is Lock Pages in Memory not enabled automatically? #

LPIM requires intentional capacity planning. When eligible SQL memory is locked, Windows has less flexibility to reclaim it during system pressure. That can improve SQL stability when Windows is trimming SQL memory, but it also increases the importance of leaving sufficient headroom for Windows and all other applications.

LPIM should therefore be paired with:

  • A documented SQL maximum-memory value
  • An inventory of other server roles
  • Monitoring of available memory and commit
  • Change control
  • Review after VM memory changes
  • A service restart during a maintenance window
  • A rollback plan

Is LPIM appropriate on a shared SQL and application server? #

It can be, but it deserves more caution than on a dedicated SQL Server. A shared server may also support reporting, document management, backup software, security tools, integrations, or web services. SQL memory must be sized around those competing workloads. The correct question is not simply, “Should LPIM be enabled?”

The better questions are:

  • Is Windows trimming SQL Server memory?
  • Is SQL Server’s maximum memory documented and appropriate?
  • How much memory do the other applications require during peak operation?
  • Does the VM host reliably provide the assigned memory?
  • What happens during backup, reporting, indexing, or maintenance?
  • Who owns future changes to the VM’s RAM allocation?

What happens if VM memory is reduced later? #

A previously safe SQL memory limit may become unsafe. For example, a SQL maximum selected for a 96 GB VM should be reviewed before reducing the VM to 64 GB or 32 GB. The SQL limit, Windows requirements, and application workload must be recalculated together. This is why the SQL memory configuration and LPIM assignment should be recorded as part of the server’s technology bookkeeping.

Did the 800 MB pagefile cause the original hard faults? #

It may have contributed significantly, but the pagefile size alone does not prove the root cause. A very small fixed pagefile reduces Windows’ total commit capacity and provides little room for temporary allocation spikes. That can worsen instability when physical memory is already under pressure.

However, hard faults may also involve:

  • Memory-mapped files
  • Application code being loaded from disk
  • Working-set trimming
  • High total memory demand
  • SQL Server and other applications competing for RAM
  • Backup or reporting workloads

Treat the pagefile as one part of the overall memory architecture.

Does a larger pagefile improve SQL performance? #

Not directly. A correctly sized pagefile can improve resilience and prevent allocation failures. It does not make pagefile-backed memory perform like RAM. If normal operations depend heavily on pagefile reads, the server still has a physical-memory, workload, or architecture problem that should be corrected.

What should be monitored after enabling LPIM? #

Monitor through at least one complete business cycle:

SQL Server
sql_memory_model_desc
locked_page_allocations_kb
physical_memory_in_use_kb
process_physical_memory_low
process_virtual_memory_low
Total Server Memory
Target Server Memory

Windows
Available MBytes
Committed Bytes
Commit Limit
Pages Input/sec
Page Reads/sec
Hard Faults/sec
Pagefile usage

Business workload
User-reported response time
Reporting periods
Indexing activity
Backup windows
Scheduled maintenance
Application-service memory use

The objective is not to force all counters to zero. The objective is stable performance without sustained memory pressure, harmful paging, or application starvation.

Final Perspective #

SQL Server optimization is not about finding one hidden setting that makes every database faster. It is about balance. SQL Server needs enough memory to cache active data efficiently. Windows needs enough memory to remain stable. Other applications need clearly understood resources. Storage must complete database requests with consistent latency. Backups must remain trustworthy. Changes must be documented and measurable.

The most valuable first step is often not advanced query tuning. It is confirming that the server’s basic architecture and configuration still match the workload it is expected to support today.

Good SQL Server management is also good technology bookkeeping:

  • Know what is active.
  • Know what owns each database.
  • Know where every file is stored.
  • Know how the server is backed up.
  • Know why each non-default setting exists.
  • Know what changed when performance improved or declined.

Those fundamentals prevent many of the performance emergencies that otherwise appear mysterious.

What are your feelings