Which databases are used within a SQL maintenance plan? - sql

I am adding an alert when a user logs into an application, if the Microsoft SQL database maintenance plan failed, did not run, was not implemented OR was never scheduled. I would prefer not to add a setting to identify the maintenance plans which should be checked.
How can I get a list of maintenance plans which perform any action on the current database "SELECT db_name()"?
I can see the list of all maintenance plans here: SELECT * FROM msdb.dbo.sysmaintplan_plans
I'm guessing that I'll need to query the plan steps and check if any contain my database.
It would be nice to be able to identify the type of each step, ie: Integrity check, Index rebuild, statistics update or backup, etc... Then I could ensure all the required steps are being accomplished.

By using the SQL profiler, I gathered several queries and put together this single SQL together which will show the log history of any maintenance plan that includes the current database. It shows each step and if it succeeded.
SELECT
ld.server_name,
mp.name AS [MTX Plan Name],
msp.subplan_name AS [Sub Plan Name],
mpl.start_time AS [JobStart],
mpl.end_time AS [JobEnd],
mpl.succeeded AS [JobSucceeded],
ld.start_time AS [StepStart],
ld.end_time AS [StepEnd],
ld.succeeded AS [StepSucceeded],
ld.line1,
ld.line2,
ld.line3,
ld.line4,
ld.line5,
ld.command
FROM
msdb.dbo.sysmaintplan_plans mp
INNER JOIN msdb.dbo.sysmaintplan_subplans msp ON mp.id = msp.plan_id
INNER JOIN msdb.dbo.sysmaintplan_log mpl ON msp.subplan_id = mpl.subplan_id
INNER JOIN msdb.dbo.sysmaintplan_logdetail ld ON mpl.task_detail_id = ld.task_detail_id
AND ld.command LIKE ('%['+db_name()+']%')
ORDER BY
mpl.start_time DESC
This works best with maintenance plans generated by the wizard.
Ad-hoc plans do not always include the command column for filtering.
But the table linking still works.

Related

When Does SQL Server Choose to Recompile Stored Procedure Execution Plans Automatically?

I am working through the following articles:
http://www.sqlservercentral.com/articles/Parameter+Sniffing/98481/
https://kohera.be/blog/sql-server/tackle-parameter-sniffing-in-sql-server-2017-and-azure-sql-database/
In both examples, if I execute the stored proc with the same parameter values more than 3 times, SQL Server (2017) seems to switch to the more correct execution plan automatically.
For example:
CREATE PROECEDURE Sales
#OrderDate datetime
AS
SELECT
sod.SalesOrderID,sod.OrderQty,sod.UnitPrice,soh.OrderDate
FROM
sales.salesorderdetail sod
INNER JOIN
sales.salesorderheader soh
ON
sod.SalesOrderID = soh.SalesOrderID
WHERE
soh.OrderDate < #OrderDate
ORDER BY
sod.UnitPrice
GO
EXEC Sales '20110730'
EXEC Sales '20140730'
If I run the top exec twice then SQL chooses Execution plan A.
If I then run the second exec, it uses Execution plan A a few times. But after 3 executions it changes to Execution plan B.
If I go back and run the first query a few times it eventually switches back to A.
Two questions. Please answer both:
How does SQL decide when to stop using the cached plan and create a new one?
Since SQL seems to automatically switch query plans after enough executions with different parameters, doesn't this make any "bad parameter sniffing" issues redundant, since SQL should correct itself after a few executions?
Please note the database in question has Parameter Sniffing switched on:

Parameter Sniffing causing slowdown for text-base query, how to remove execution plan?

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/

Is there a microsoft SQL query result cache equivalent?

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'

SQL Server function intermittent performance issues

We have a function in our database that searches two large tables to see if a value exists. It is a pretty large query, but it is optimized to use indexes and generally runs pretty fast.
Three times over the past 2 weeks, this function decided to go haywire and run extremely slow, which causes deadlocking and bad performance all around. This happens even at times of less than peak usage.
Rebuilding the function using "Alter Function" in SQL Server seems to take care of the issue. Once we do that, the server usage goes back to normal and everything is OK.
This leads us to think that the functions query plan has rebuilt, and is taking the correct indexes into account, but we have no idea why SQL Server decided to change the query plan to a worse plan all of a sudden.
Does anyone have any ideas what might cause this behavior, or how to test for it, or prevent it? We are running SQL Server 2008 Enterprise.
The behaviour you are describing is often due to an incorrectly cached query plan and/or out of date statistics.
It commonly occurs when you have a large number of parameters in a WHERE clause, especially a long list of those that are of the form:
(#parameter1 is NULL OR TableColumn1 = #parameter1)
Say, the cached query plan expires, and the proc is called with an unrepresentative set of parameters. The plan is then cached for this data profile. BUT, if the proc is more oftenly common with a very different set of parameters, the plan might not be appropriate. This is often known as 'parameter sniffing'.
There are ways to mitigate and eliminate this problem but they may involve trade-offs and depend on your SQL Server version. Look at OPTIMIZE FOR and OPTIMIZE FOR UNKNOWN. IF (and it's a big if) the proc is called infrequently but must run as fast as possible you can mark it as OPTION(RECOMPILE), to force a recompile each time it is called, BUT don't do this for frequently called procs OR without investigation.
[NOTE: be aware of which Service pack and Cumulative Update (CU) your SQL Server 2008 box has, as the recompile and parameter sniffing logic works differently in some versions]
Run this query (from Glenn Berry) to determine the state of statistics:
-- When were Statistics last updated on all indexes?
SELECT o.name, i.name AS [Index Name],
STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date],
s.auto_created, s.no_recompute, s.user_created, st.row_count
FROM sys.objects AS o WITH (NOLOCK)
INNER JOIN sys.indexes AS i WITH (NOLOCK)
ON o.[object_id] = i.[object_id]
INNER JOIN sys.stats AS s WITH (NOLOCK)
ON i.[object_id] = s.[object_id]
AND i.index_id = s.stats_id
INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK)
ON o.[object_id] = st.[object_id]
AND i.[index_id] = st.[index_id]
WHERE o.[type] = 'U'
ORDER BY STATS_DATE(i.[object_id], i.index_id) ASC OPTION (RECOMPILE);

SQL Server 2000: How can I tell how many plans a stored procedure has cached?

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)