Skip to main content

Command Palette

Search for a command to run...

Caching in SQL Server

Updated
4 min readView as Markdown

In SQL Server, caching is the primary mechanism used to optimize performance by reducing physical disk I/O and CPU overhead. It works by storing data and execution logic in memory (RAM) so they can be retrieved instantly rather than reading from the slow hard drive or recalculating complex logic.

The "usage" of caching in SQL Server can be broken down into two categories: Internal Usage (how SQL Server automatically uses it) and Administrative Usage (how you configure and manage it).


1. Internal Usage: How SQL Server Uses Cache Automatically

SQL Server manages memory dynamically. You do not need to manually "load" data into the cache; the engine handles this through two main components:

A. The Buffer Pool (Data Cache)

This is the largest consumer of memory. Its purpose is to reduce Disk I/O.

  • Reading Data: When you run a SELECT query, SQL Server first checks the Buffer Pool. If the data page is there (a "Logical Read"), it returns it immediately. If not, it reads it from the disk (a "Physical Read") and places it into the Buffer Pool for future use.

  • Writing Data: When you UPDATE or INSERT data, SQL Server modifies the page in memory (making it a "Dirty Page"). It acknowledges the write to you immediately but writes the changes to the actual disk file later in the background (a process called "Checkpoint").

  • LRU Policy: If memory fills up, SQL Server uses a "Least Recently Used" (LRU) algorithm to evict old data pages that haven't been accessed recently to make room for new ones.

B. The Plan Cache (Procedure Cache)

This component reduces CPU Usage.

  • Compilation: Generating an "Execution Plan" (the roadmap of how to find your data) is CPU-intensive.

  • Reuse: When you run a query (e.g., SELECT * FROM Users WHERE ID = 1), SQL Server saves the execution plan. If you run the same query again (even with a different ID, if parameterized correctly), it reuses the cached plan instead of compiling a new one.


2. Administrative Usage: How You Configure & Manage It

While SQL Server manages caching automatically, a Database Administrator (DBA) must configure the boundaries to prevent the server from crashing the OS.

A. Memory Configuration (Critical)

By default, SQL Server will consume all available RAM, potentially starving the Operating System and causing the server to freeze. You must set limits:

  • Max Server Memory: Caps the amount of RAM SQL Server can use for the Buffer Pool.

    • Rule of Thumb: Leave at least 4GB–6GB (or 10–15%) of RAM for the OS.
  • Min Server Memory: Guarantees a baseline amount of memory for SQL Server so it doesn't release it back to the OS under pressure.

T-SQL to Configure:

EXEC sys.sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
-- Set Max Memory to 50 GB (Value is in MB)
EXEC sys.sp_configure 'max server memory (MB)', 51200;
GO
RECONFIGURE;
GO

B. Optimizing for Ad Hoc Workloads

If your application sends many unique queries (non-parameterized), your Plan Cache can bloat, wasting memory.

  • Usage: Enable the "Optimize for Ad hoc Workloads" setting.

  • Effect: When a unique query runs for the first time, SQL Server stores only a tiny "stub" in memory. It only stores the full, large plan if that query is run a second time.

C. Forcing Plan Recompilation

Sometimes a cached plan is "bad" (e.g., optimized for a small dataset but now you are querying a large one). You may need to manually clear the cache.

  • Clear All Plans (Use with Caution): DBCC FREEPROCCACHE

  • Clear Specific Plan: Find the plan handle and clear only that one to avoid slowing down the whole server.


3. Monitoring Usage

You can query Dynamic Management Views (DMVs) to see exactly what is in your cache.

Check Data Cache (What tables are in memory?)

This query shows which tables are currently consuming the most RAM in the buffer pool:

SELECT 
    OBJECT_NAME(p.object_id) AS [TableName],
    COUNT(*) * 8 / 1024 AS [Buffer_Size_MB],
    COUNT(*) AS [Buffer_Page_Count]
FROM sys.allocation_units AS a
INNER JOIN sys.dm_os_buffer_descriptors AS b ON a.allocation_unit_id = b.allocation_unit_id
INNER JOIN sys.partitions AS p ON a.container_id = p.hobt_id
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY [Buffer_Size_MB] DESC;

Check Plan Cache (What queries are cached?)

This checks for "bloat" by finding plans that were created but only used once:

SELECT 
    cp.objtype AS [CacheType],
    COUNT(*) AS [TotalPlans],
    SUM(CAST(cp.size_in_bytes AS BIGINT)) / 1024 / 1024 AS [TotalSizeMB],
    SUM(CASE WHEN cp.usecounts = 1 THEN 1 ELSE 0 END) AS [SingleUsePlans]
FROM sys.dm_exec_cached_plans AS cp
GROUP BY cp.objtype
ORDER BY [TotalSizeMB] DESC;

Summary

FeatureBenefitPrimary Resource Saved
Buffer PoolData is read from RAM instead of slow Disk.Disk I/O
Plan CacheLogic is reused instead of re-compiled.CPU
Buffer Pool ExtensionExtends RAM cache to an SSD (faster than HDD).Disk I/O

More from this blog

S

SQL Insights

31 posts