If you remember, SQL Server takes your stored procedure and rewrites it, then prepares a plan. This process is called ‘compilation’. If it can, it then executes the prepared plan rather than interpreting the query anew each time.
These plans are stored in an area called the ‘procedure cache’. Plans are retained in the cache based on a number of factors such as amount of server memory, plan cost, and current memory pressure. The engine will get rid of infrequently used plans before frequently used ones, and cheap plans before expensive ones.
You can, and often will, get multiple plans for some procedures in cache. Predicting how many plans there will be is not an exact science, but in general the more complex the arguments to your procedure, the more plans will be in cache, because the engine will create a different plan if you’re looking for all orders from Chicago than if you’re looking for all orders with total > $1000.
Here is a query that will let you see all plans in cache for a given object (a stored procedure is an object in SQL Server), as well as some useful and interesting information about those plans.
Apologies for the style – the mix of camelcase and under_score names is due to my schizophrenia on this point. I used to be exclusively one, but this place uses the other, and when I write queries that use DMVs I get all split-personality like.
Usecounts = number of times the plan has been used.
Plan_comp_time = the time that this plan was compiled.
Last_execution_time = the time that this plan was last executed.
HoursOld = length of time, in hours, that this plan has been in cache.
HoursUntouched = length of time, in hours, since this plan was last executed.
Execution_count = number of times this plan has been executed.
AvgReads = average number of pages read during an execution.
Max_logical_reads = the highest number of pages read during an execution.
Avg_time = average time, in milliseconds, that this plan took to complete.
Total_elapsed_time = total time – an indicator of total cost, since this is the sum of all times for this plan.
last_elapsed_time = the time for the last execution.
min_elapsed_time = the shortest time for an execution
max_elapsed_time = the longest time for an execution
cp.usecounts,
qs.creation_time AS plan_comp_time,
qs.last_execution_time,
CONVERT(VARCHAR(5), DATEDIFF(hh, qs.creation_time, GETDATE())) AS HoursOld,
CONVERT(VARCHAR(5), DATEDIFF(hh, last_execution_time, GETDATE())) AS HoursUntouched,
qs.execution_count,
qs.total_logical_reads/qs.execution_count AS AvgReads,
qs.max_logical_reads,
qs.total_elapsed_time/qs.execution_count AS AvgTime,
qs.total_elapsed_time,
qs.last_elapsed_time,
qs.min_elapsed_time,
qs.max_elapsed_time
FROM sys.dm_exec_cached_plans cp
JOIN sys.dm_exec_query_stats qs
ON cp.plan_handle = qs.plan_handle
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
JOIN sys.objects o
ON o.OBJECT_ID = st.objectid
WHERE o.name LIKE ‘%SomeProcedureName%’
– ORDER BY hoursuntouched DESC
1 Billion
My boss was stomping around agitated because The Business has some heavy data requests. He had written something some time ago that got them something close to what HE thought THEY thought they needed.
I knew that this wasn’t what they really needed, but let him go ahead and send a sample of the data off anyway. Most times when people senior to you have their minds made up, there’s no point in arguing.
“It’s pretty fast,” he said, “if you need the code. It takes about an hour per partition.”
On our system, some of the really big tables are pseudo-partitions – separate tables with identical structures and similar names. Orders1, Orders2, Orders3, etc. He meant it took about an hour to process each one of these tables.
What I really needed was a subset of that data. About 12%, as it turns out. So I politely acknowledged his offer of Free Code! and wrote something that processed the first 16 partitions. It completed in about 2 hours 20 minutes.
As a measure of how much data this is, this is the rowcount of the largest table after the first 16 partitions were done. Remember, this rowcount is about 12% of the data.
———–
109734329
I have another set of partitions to process today, which will a bit more than double this total.
Yes, if take the time to do the math you will see that the base data is more than 1 billion rows.