What Query Plans are in SQL Server's Memory?

By Bill Graziano on 25 July 2007 | 4 Comments | Tags: Memory Tuning


SQL Server memory is primarily used to store data (buffer) and query plans (procedure cache). In this article I'll show how much memory is allocated to the procedure cache (RAM). I'll explain how to determine what plans are in the cache and how often they're used.

SQL Server stores the procedure cache in 8KB data pages.  You can use the dynamic management view sys.dm_os_memory_cache_counters to provide a summary of how the cache is allocated using this query:

SELECT  TOP 6
	LEFT([name], 20) as [name],
	LEFT([type], 20) as [type],
	[single_pages_kb] + [multi_pages_kb] AS cache_kb,
	[entries_count]
FROM sys.dm_os_memory_cache_counters 
order by single_pages_kb + multi_pages_kb DESC

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

name                 type                             cache_kb        entries_count
-------------------- -------------------- -------------------- --------------------
SQL Plans            CACHESTORE_SQLCP                   669880                 9613
Object Plans         CACHESTORE_OBJCP                    14120                   97
Bound Trees          CACHESTORE_PHDR                      3288                   63
SchemaMgr Store      USERSTORE_SCHEMAMGR                  2544                    0
mssqlsystemresource  USERSTORE_DBMETADATA                 2080                  241
sqlteam              USERSTORE_DBMETADATA                  728                  302
. . . . .

On the server that hosts SQLTeam.com this query actually returns 75 rows.  The server has 2GB of RAM with 1GB allocated to SQL Server 2005 Express Edition.  This article will focus on the first three rows in this query.  These are:

  • CACHESTORE_OBJCP. These are compiled plans for stored procedures, functions and triggers.
  • CACHESTORE_SQLCP.  These are cached SQL statements or batches that aren't in stored procedures, functions and triggers.  This includes any dynamic SQL or raw SELECT statements sent to the server.
  • CACHESTORE_PHDR.  These are algebrizer trees for views, constraints and defaults.  An algebrizer tree is the parsed SQL text that resolves the table and column names.

Notice that there are very few compiled plans for stored procedures (CACHESTORE_OBJCP).  This should work out to about one plan per active stored procedure on the server.  Also notice that there are lots and lots of plans for dynamic SQL on the server (CACHESTORE_SQLCP).  The forum software on the site doesn't use stored procedures.  The SQL statements it generates go into the SQL plan cache.

You can monitor the number of data pages in the plan cache using Performance Monitor (PerfMon) using SQLServer:Plan Cache object with the Cache Pages counter.  There are instances for SQL Plans (CACHESTORE_SQLCP), Object Plans (CACHESTORE_OBJCP) and Bound Trees (CACHESTORE_PHDR).

We can see individual cache entries by using the sys.dm_exec_cached_plans dynamic management view.

SELECT usecounts, cacheobjtype, objtype, plan_handle
FROM sys.dm_exec_cached_plans

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

  usecounts cacheobjtype     objtype              plan_handle
----------- ---------------- -------------------- --------------------------------------------------
      23133 Compiled Plan    Proc                 0x05000600E969C702B861712D000000000000000000000000
       6193 Compiled Plan    Adhoc                0x060005009D7DB935B841F141000000000000000000000000
       6192 Compiled Plan    Trigger              0x05000500E9DB0F6BB8E13359000000000000000000000000
       6192 Compiled Plan    Proc                 0x0500050047E57235B8C1560F000000000000000000000000
       6097 Compiled Plan    Adhoc                0x06000500992FE330B8C16E59000000000000000000000000
       6082 Compiled Plan    Adhoc                0x06000500EFE7B508B861CD0D000000000000000000000000
       5818 Compiled Plan    Trigger              0x050005003FB5C870B8614559000000000000000000000000
       4864 Compiled Plan    Prepared             0x06000500F264B12FB8412F2B000000000000000000000000
       4850 Compiled Plan    Prepared             0x0600050017A8CC01B8812B48000000000000000000000000
       3385 Compiled Plan    Proc                 0x05000500099CB87DB801A449000000000000000000000000
       884 Parse Tree        View                 0x0500FF7FC1010000C800130D000000000000000000000000
. . . . .

This query lists the most used query plans.  In includes plans for stored procedures, adhoc or dynamic SQL, triggers, prepared SQL and views.  If we want to see the SQL associates with these plans like need to use the sys.dm_exec_sql_text dynamic management function like this:

select  TOP 100
	objtype, 
	p.size_in_bytes,
	LEFT([sql].[text], 100) as [text]
from sys.dm_exec_cached_plans p
outer apply sys.dm_exec_sql_text (p.plan_handle) sql
ORDER BY usecounts DESC

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

objtype size_in_bytes text
------- ------------- ------------------------------------------------------------------------------------
Proc           172032 CREATE PROC [dbo].[subtext_GetSingleEntry] ( @ID int = NULL, @EntryName nvarchar(...
Adhoc           24576 SELECT F_PRIVATEFORUMS, F_SUBJECT, F_PASSWORD_NEW  FROM FORUM_FORUM  WHERE FORUM...
View            73728 CREATE VIEW [dbo].[sqlteam_Article_View] AS SELECT bbo.sqlteam_Article.ArticleID,...
Proc          4251648 CREATE PROCEDURE [BMP_proc_RetrieveBannerFromZoneSite] (@ZoneID [int],@SiteID ...
Proc           425984 CREATE PROC [dbo].[sqlteam_Article_Read_ByPageName] @PageName VARCHAR(200) AS ...

I manually pulled a few rows from the result set to highlight the type of results this query generates.  Notice that the compile query plans are BIG.  One listed in over 4MB.  There many of them that are roughly 400KB.  If you do a little math on the first result set in this article you'll see the average SQL plan is just under 70KB and the average stored procedure plan is 145KB.  Stored procedures tend to encapsulate more complex statements so that doesn't surprise me.

This should give you enough information to go through your query plans and see what's being used, what's rarely used and how much space they take up.

Discuss this article: 4 Comments so far. Print this Article.

If you like this article you can sign up for our weekly newsletter. There's an opt-out link at the bottom of each newsletter so it's easy to unsubscribe at any time.

Email Address:

Related Articles

What Data is in SQL Server's Memory? (23 July 2007)

Inside SQL Server 2000's Memory Management Facilities (29 January 2004)

HOW TO: Configure Memory for More Than 2 GB in SQL Server (Q274750) (10 June 2002)

Configure Memory for More Than 2 GB in SQL Server (8 April 2002)

Other Recent Forum Posts

adding a date seems to remove any null values (3 Replies)

trx date time = system date time (1 Reply)

7 day sales analysis query (3 Replies)

sql every hour sales total by different shop (3 Replies)

Sum where date is between two dates (3 Replies)

Query into text file: bcp, dynamic sql & tables (0 Replies)

Convert DateTime to Int (1 Reply)

Truncate trans logs (3 Replies)

Subscribe to SQLTeam.com

Weekly SQL Server newsletter with articles, forum posts, and blog posts via email. Subscribers receive our white paper with performance tips for developers.

SQLTeam.com Articles via RSS

SQLTeam.com Weblog via RSS

- Advertisement -