I'm working with a tool that shows some counts from a table in a UI.
To get those numbers a singe query is executed every 5 seconds. I cannot make any structural changes in the tool, but I am able to change the query the gets the counts.
The problem is that the execution of the query can take up to 5 seconds, in wich the user can't do anything. The data that the query is fetching only changes like every few minutes.
The tool can run both on Oracle and MSSQL. In Oracle I was able to greatly improve the speed of the query by using the query result cache (added the /*+ RESULT_CACHE */ hint to the query). Since the result of the query only changes every now and then, caching it is a usable solution in this specific case. The executing time goes to something like 1ms instead of the 5 secodns it was before.
I was wondering if there is a equivalent in Microsoft SQL.
SQL Server Management Studio has the ability to show a query execution plan that shows the percentage of time spent on each part of a query. From the Query menu, investigate the "Display estimated execution plan" and "Include actual execution plan" menu items.
There's also a SQL Server query plan cache:
-- First, clear the cache.
-- WARNING: Do not execute this statement anywhere near production!
DBCC FREEPROCCACHE
-- Look at what executable plans are in cache
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'
-- Execute the following statement
SELECT t.*
FROM pubs.dbo.titles AS t
WHERE t.price = 19.99
-- Look at what executable plans are in cache and you'll
-- find that there's a plan for a NUMERIC(4,2)
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'
-- If you execute the EXACT same statement with a 4,2
-- then you will get THAT plan. But if you execute with a 5,2
-- then you'll get a new plan. Try this:
SELECT t.*
FROM pubs.dbo.titles AS t
WHERE price = 199.99
-- Look again at the cached executable plans, and you'll see a NEW one...
SELECT sc.*
FROM master.dbo.syscacheobjects AS sc
WHERE sc.cacheobjtype = 'Executable Plan'
Related
I have a stored procedure that runs every 5 minutes in a job on SQL server. The job will run for 80% of the time with no results , this is expected, but when it does have data to process it is a very long process.
The code is like this below simplified.
IF exists (Select top 1 col1 from tbl1 where processed = '0' )
BEGIN
HUGE PROCESS with multiple selects joins and updates
END
How will the execution plan evaluate this SP? Is this a rare case that using with WITH RECOMPILE is the best option?
If you use Include Actual Execution Plan option in the SQL Server Management Studio, you will see that when the IF expression is evaluated to false its body's operators are not included in the execution plan.
So, there is no need to worry - the SQL Engine will use correct execution plan and will not touch the data.
The recompile option can be helpful in particular queries but I believe you can skip it for now.
I'm debugging a parameter sniffing issue in SQL Server 2014.
My application performs a query that along the lines of: (drastically reduced for simplicity)
SELECT somefields FROM MyTable Where anotherField = #myParameter
Where #myParameter is added through the command.Parameters.Add() method, this query takes too long to run and times out.
When trying to replicate the issue, I went to SSMS and tried the following query:
DECLARE #myParameter int = 10 --same value as in the code
SELECT somefields FROM MyTable Where anotherField = #myParameter
And the query runs fast with a different execution plan from the code.
I want to try some tweaks to the query to see if I can improve my code's execution plan, but I need a ways to make SSRS behave the way my code does.
How can I write my query in SSRS, so that SQL Server calculates the execution plan in the same way it does for my application?
I have a sql query, the exact code of which is generated in C#, and passed through ADO.Net as a text-based SqlCommand.
The query looks something like this:
SELECT TOP (#n)
a.ID,
a.Event_Type_ID as EventType,
a.Date_Created,
a.Meta_Data
FROM net.Activity a
LEFT JOIN net.vu_Network_Activity na WITH (NOEXPAND)
ON na.Member_ID = #memberId AND na.Activity_ID = a.ID
LEFT JOIN net.Member_Activity_Xref ma
ON ma.Member_ID = #memberId AND ma.Activity_ID = a.ID
WHERE
a.ID < #LatestId
AND (
Event_Type_ID IN(1,2,3))
OR
(
(na.Activity_ID IS NOT NULL OR ma.Activity_ID IS NOT NULL)
AND
Event_Type_ID IN(4,5,6)
)
)
ORDER BY a.ID DESC
This query has been working well for quite some time. It takes advantage of some indexes we have on these tables.
In any event, all of a sudden this query started running really slow, but ran almost instantaneously in SSMS.
Eventually, after reading several resources, I was able to verify that the slowdown we were getting was from poor parameter sniffing.
By copying all of the parameters to local variables, I was able to successfully reduce the problem. The thing is, this just feels like all kind of wrong to me.
I'm assuming that what happened was the statistics of one of these tables was updated, and then by some crappy luck, the very first time this query was recompiled, it was called with parameter values that cause the execution plan to differ?
I was able to track down the query in the Activity Monitor, and the execution plan resulting in the query to run in ~13 seconds was:
Running in SSMS results in the following execution plan (and only takes ~100ms):
So what is the question?
I guess my question is this: How can I fix this problem, without copying the parameters to local variables, which could lead to a large number of cached execution plans?
Quote from the linked comment / Jes Borland:
You can use local variables in stored procedures to “avoid” parameter sniffing. Understand, though, that this can lead to many plans stored in the cache. That can have its own performance implications. There isn’t a one-size-fits-all solution to the problem!
My thinking is that if there is some way for me to manually remove the current execution plan from the temp db, that might just be good enough... but everything I have found online only shows me how to do this for an actual named stored procedure.
This is a text-based SqlCommand coming from C#, so I do not know how to find the cached execution plan, with the sniffed parameter values, and remove it?
Note: the somewhat obvious solution of "just create a proper stored procedure" is difficult to do because this query can get generated in a number of different ways... and would require a somewhat unpleasant refactor.
If you want to remove a specific plan from the cache then it is really a two step process: first obtain the plan handle for that specific plan; and then use DBCC FREEPROCCACHE to remove that plan from the cache.
To get the plan handle, you need to look in the execution plan cache. The T-SQL below is an example of how you could search for the plan and get the handle (you may need to play with the filter clause a bit to hone in on your particular plan):
SELECT top (10)
qs.last_execution_time,
qs.creation_time,
cp.objtype,
SUBSTRING(qt.[text], qs.statement_start_offset/2, (
CASE
WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.[text])) * 2
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2 + 1
) AS query_text,
qt.text as full_query_text,
tp.query_plan,
qs.sql_handle,
qs.plan_handle
FROM
sys.dm_exec_query_stats qs
LEFT JOIN sys.dm_exec_cached_plans cp ON cp.plan_handle=qs.plan_handle
CROSS APPLY sys.dm_exec_sql_text (qs.[sql_handle]) AS qt
OUTER APPLY sys.dm_exec_query_plan(qs.plan_handle) tp
WHERE qt.text like '%vu_Network_Activity%'
Once you have the plan handle, call DBCC FREEPROCCACHE as below:
DBCC FREEPROCCACHE(<plan_handle>)
There are many ways to delete/invalidate a query plan:
DBCC FREEPROCCACHE(plan_handle)
or
EXEC sp_recompile 'net.Activity'
or
adding OPTION (RECOMPILE) query hint at the end of your query
or
using optimize for ad hoc workloads server settings
or
updating statistics
If you have a crappy product from a crappy vendor, the best way to handle parameter sniffing is to create you own plan using EXEC sp_create_plan_guide/
execute very slowly on below sql statement, env: oracle 9. Please advise the cause or hints to debug. Thanks a lot .
INSERT INTO tmp_table (col1,col2,col3,col4,col5,col6,col7,col8,col9)
select * from my_view where col1 = 1;
How far i tested: execute the select sub-statement cost 3 sec to get 1 record returned while endless executing but no resultset returned when execute the entire statement, like hanging.
When a query appears to execute quickly, in the sense that the last row is returned quickly rather than just the first row, but it runs slowly when used in an insert statement, the usual suspects are:
A change in the execution plan, driven by the optimiser believing that an all_rows goal is now appropriate where previously a first_rows goal was used. Check the execution plan for changes.
Some action being executed as a result of the insert. Slow triggers on the target table, or materialised view logging, are possible causes. This would not be the case when running "create table ... as select ..".
Sometimes when diagnosing issues with our SQL Server 2000 database it might be helpful to know that a stored procedure is using a bad plan or is having trouble coming up with a good plan at the time I'm running into problems. I'm wondering if there is a query or command I can run to tell me how many execution plans are cached currently for a particular stored procedure.
You can query the cache in a number of different ways, either looking at its contents, or looking at some related statistics.
A couple of commands to help you along your way:
SELECT * FROM syscacheobjects -- shows the contents of the procedure
-- cache for all databases
DBCC PROCCACHE -- shows some general cache statistics
DBCC CACHESTATS -- shows the usage statistics for the cache, things like hit ratio
If you need to clear the cache for just one database, you can use:
DBCC FLUSHPROCINDB (#dbid) -- that's an int, not the name of it.
-- The int you'd get from sysdatabases or the dbid() function
Edit: above the line is for 2000, which is what the question asked. However, for anyone visiting who's using SQL Server 2005, it's a slightly different arrangement to the above:
select * from sys.dm_exec_cached_plans -- shows the basic cache stuff
A useful query for showing plans in 2005:
SELECT cacheobjtype, objtype, usecounts, refcounts, text
from sys.dm_exec_cached_plans p
join sys.dm_exec_query_stats s on p.plan_handle = s.plan_handle
cross apply sys.dm_exec_sql_text(s.sql_handle)