Last Run Date on a Stored Procedure in SQL Server - sql-server

We starting to get a lot of stored procedures in our application. Many of them are for custom reports many of which are no longer used. Does anyone know of a query we could run on the system views in SQL Server 2005 that would tell us the last date a stored procedure was executed?

The below code should do the trick (>= 2008)
SELECT o.name,
ps.last_execution_time
FROM sys.dm_exec_procedure_stats ps
INNER JOIN
sys.objects o
ON ps.object_id = o.object_id
WHERE DB_NAME(ps.database_id) = ''
ORDER BY
ps.last_execution_time DESC
Edit 1 : Please take note of Jeff Modens advice below. If you find a procedure here, you can be sure that it is accurate. If you do not then you just don't know - you cannot conclude it is not running.

In a nutshell, no.
However, there are "nice" things you can do.
Run a profiler trace with, say, the stored proc name
Add a line each proc (create a tabel of course)
"INSERT dbo.SPCall (What, When) VALUES (OBJECT_NAME(##PROCID), GETDATE()"
Extend 2 with duration too
There are "fun" things you can do:
Remove it, see who calls
Remove rights, see who calls
Add RAISERROR ('Warning: pwn3d: call admin', 16, 1), see who calls
Add WAITFOR DELAY '00:01:00', see who calls
You get the idea. The tried-and-tested "see who calls" method of IT support.
If the reports are Reporting Services, then you can mine the RS database for the report runs if you can match code to report DataSet.
You couldn't rely on DMVs anyway because they are reset om SQL Server restart.
Query cache/locks are transient and don't persist for any length of time.

Oh, be careful now! All that glitters is NOT gold! All of the “stats” dm views and functions have a problem for this type of thing. They only work against what is in cache and the lifetime of what is in cache can be measured in minutes. If you were to use such a thing to determine which SPs are candidates for being dropped, you could be in for a world of hurt when you delete SPs that were used just minutes ago.
The following excerpts are from Books Online for the given dm views…
sys.dm_exec_procedure_stats
Returns aggregate performance statistics for cached stored procedures. The view contains one row per stored procedure, and the lifetime of the row is as long as the stored procedure remains cached. When a stored procedure is removed from the cache, the corresponding row is eliminated from this view.
sys.dm_exec_query_stats
The view contains one row per query statement within the cached plan, and the lifetime of the rows are tied to the plan itself. When a plan is removed from the cache, the corresponding rows are eliminated from this view.

sys.dm_exec_procedure_stats contains the information about the execution functions, constraints and Procedures etc. But the life time of the row has a limit, The moment the execution plan is removed from the cache the entry will disappear.
Use [yourDatabaseName]
GO
SELECT
SCHEMA_NAME(sysobject.schema_id),
OBJECT_NAME(stats.object_id),
stats.last_execution_time
FROM
sys.dm_exec_procedure_stats stats
INNER JOIN sys.objects sysobject ON sysobject.object_id = stats.object_id
WHERE
sysobject.type = 'P'
ORDER BY
stats.last_execution_time DESC
This will give you the list of the procedures recently executed.
If you want to check if a perticular stored procedure executed recently
SELECT
SCHEMA_NAME(sysobject.schema_id),
OBJECT_NAME(stats.object_id),
stats.last_execution_time
FROM
sys.dm_exec_procedure_stats stats
INNER JOIN sys.objects sysobject ON sysobject.object_id = stats.object_id
WHERE
sysobject.type = 'P'
and (sysobject.object_id = object_id('schemaname.procedurename')
OR sysobject.name = 'procedurename')
ORDER BY
stats.last_execution_time DESC

If you enable Query Store on SQL Server 2016 or newer you can use the following query to get last SP execution. The history depends on the Query Store Configuration.
SELECT
ObjectName = '[' + s.name + '].[' + o.Name + ']'
, LastModificationDate = MAX(o.modify_date)
, LastExecutionTime = MAX(q.last_execution_time)
FROM sys.query_store_query q
INNER JOIN sys.objects o
ON q.object_id = o.object_id
INNER JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE o.type IN ('P')
GROUP BY o.name , + s.name

This works fine on 2005 (if the plan is in the cache)
USE YourDb;
SELECT qt.[text] AS [SP Name],
qs.last_execution_time,
qs.execution_count AS [Execution Count]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = DB_ID()
AND objectid = OBJECT_ID('YourProc')

I use this:
use YourDB;
SELECT
object_name(object_id),
last_execution_time,
last_elapsed_time,
execution_count
FROM
sys.dm_exec_procedure_stats ps
where
lower(object_name(object_id)) like 'Appl-Name%'
order by 1

Related

How to find SQL Object having the text in SQL Server?

There was some performance issue in my application in production, I did some investigation and found out that one process is blocking my SP execution. I saw the log in SolarWinds DPA and found out that the process having id 12345 is blocking my SP. then it is showing the query in SQL text.
Query which is blocking
SELECT ColX, ColY.........
FROM [dbo].[Table1] As T1
INNER JOIN [dbo].[Table2] AS T2
ON T1.[PaymentFK] = T2.[PaymentPK]
WHERE (([Col1] = #p0)
OR ([ExtBCol1atchFileFK] IS NULL))
AND ([Col2] = #p1)
AND ([Col3] = #p2)
AND (NOT ([Col4] = 1))
But not giving object names like SP/View/Trigger/Job. I searched this text in all the SPs/Views/Triggers. But could not find the blocking query.
So is there any way to find out in which object exactly this query is being used?
This might help if the script is stored in the database.
SELECT DISTINCT OBJECT_SCHEMA_NAME(object_id), OBJECT_NAME(object_id)
FROM sys.sql_modules (NOLOCK)
WHERE definition LIKE '%search_phrase%'

Find ColumnNames or TableNames as reserved keyword in SQL Server stored procedure

I have plenty of stored procedures in my database. All are designed to return result sets. I followed naming standards with all keywords are UPPERCASE so if any column name or table name as reserved keyword in any of the SELECT statement then that would be in UPPERCASE.
I want to convert those UPPERCASE keywords to camel case.
For example one of my actual stored procedures:
CREATE PROCEDURE prc_getresults
AS
BEGIN
SELECT ZD.Id
,ZD.NAME
,ZD.TIMESTAMP
,ZD.CreatedBy
FROM ZoneDetails ZD
INNER JOIN ZONE Z ON Z.Id = ZD.ZoneId
END
My expected code after conversion would be
CREATE PROCEDURE prc_getresults
AS
BEGIN
SELECT ZD.Id
,ZD.Name
,ZD.TimeStamp
,ZD.CreatedBy
FROM ZoneDetails ZD
INNER JOIN Zone Z ON Z.Id = ZD.ZoneId
END
Here please look at the column name TimeStamp, Name and table Zone.
There are around 700+ stored procedures. I am unable to open each and every code and edit these manually.
Kindly provide me any ideas to better implement these changes to all stored procedures in the database.
You can extend the below query for your need,
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc
FROM sys.sql_modules m
INNER JOIN
sys.objects o
ON m.object_id = o.object_id
WHERE m.definition In ( '%\[TimeStamp\]%', '%\[Name\]%', '%\[Zone\]%');
You'd better download this fantastic free tool - http://www.red-gate.com/products/sql-development/sql-search/ - The Red-date search for sql server.
Then you have to do some work finding the reserved words - https://msdn.microsoft.com/en-us/library/ms189822.aspx
The tool offers you a very good visibility of the things.

How do I find all stored procs and functions that changes data in a given table?

It is easy to find all stored procs that “depends” on a given table by using Juneau (CTP3) or SQL Dependency Tracker (from RedGate).
However we have 100s of stored procs that just select from the given table, and hence make it very time consuming to look at the results from Juneau.
I need to find the procs that insert/update/delete data from the table.
(A search with a complex regex, is not a solution that will work!)
With the same caveats as Christian, that there isn't really a way to be 100% certain that a stored procedure updates your table and not another, this method has a couple of improvements:
it uses sys.sql_modules, so no chance of missing a hit due to a boundary, or not capturing all of the text, for procs > 4k
it doesn't parse the object text for the table name, which can lead to a lot of false positives (table name in comments only, table name is part of a larger name)
it generates an sp_helptext command for each potential match, so you can copy & paste the output into the top pane, run it, and quickly scan to figure out if there are any false positives.
Code:
SELECT 'EXEC sp_helptext '''
+ QUOTENAME(SCHEMA_NAME(p.[schema_id]))
+ '.' + QUOTENAME(p.name) + ''';'
FROM sys.procedures AS p
INNER JOIN sys.sql_modules AS m
ON p.[object_id] = m.[object_id]
INNER JOIN sys.sql_expression_dependencies AS d
ON p.[object_id] = d.referencing_id
WHERE d.referenced_id = OBJECT_ID('dbo.your_table_name')
AND
(
LOWER(m.[definition]) LIKE '%update%'
OR LOWER(m.[definition]) LIKE '%insert%'
OR LOWER(m.[definition]) LIKE '%delete%'
);
Now one weakness is that sys.sql_expression_dependencies isn't 100% dependable - but I'd still prefer to do it this way for the above reasons.
I wrote a pretty lengthy article about maintaining dependencies a while back:
Keeping sysdepends up to date in SQL Server 2008
You can query the system views for that.
Here is an example how to find all SPs which are related to a certain table.
With a bit of modification, you can find only those that actually contain the keywords delete, insert and update:
SELECT DISTINCT so.name, sc.text
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE (sc.TEXT LIKE '%your_table%' AND sc.TEXT LIKE '%delete%')
OR (sc.TEXT LIKE '%your_table%' AND sc.TEXT LIKE '%insert%')
OR (sc.TEXT LIKE '%your_table%' AND sc.TEXT LIKE '%update%')
This is not a perfect solution (for example, it will also find SPs which SELECT from your table and DELETE from another), but if you have hundreds of SPs which only SELECT from your table and do nothing else, at least these will be filtered out.
In the end, I just did a string search over the folders that store the master copy of the stored procs. It took a few hours to look at all the hits, but that was quicker than trying to write my own tool.
(I don’t understand why the tooling for SQL is so limited compared to C# for this sort of thing)
**
Try this SP_Helptrigger 'table name' sp_helptext'triggername' see the
code and then view the manipulation part in the trigger
**

How to stop stored procs from whining about a missing column that I am about to delete in SQL Server 2008?

I am deleting a column from one of the frequently used tables in my database.
Last time I did this errors started to crawl up from all sorts of stored procs that I had long forgotten existed; complaining about the missing column. (only when that stored proc was called)
so, I dont want to get winded up with these things again, I want to make sure all stored procs are free of that column before I actually delete it.
What is the best way to search through all stored procs (and I have quite a lot of them) and remove the reference to that column?
I tried to find an option in the menu to do this but I did not find anything very obvious to do this.
any help, (other than telling me to go through them all one by one) is appreciated.
ps: of course, doesnt mean that I will depreciate your comment if you do tell me. I will only downvote :P
(nah, just kidding!)
To add to the various TSQL solutions, there is a free tool from Red Gate that integrates into SSMS: SQL Search
Use this script. It will also return triggers. If many tables has column with the same name you can add tale name to the where too. This script works on MSSQL 2000, 2005. I haven't tested it on 2008, but it should work fine too.
SELECT o.name
FROM sysobjects o
INNER JOIN syscomments c ON o.id = c.id
WHERE c.text like '%column_name%'
Edit: If you want to filter it only to store procedures add AND type ='P' to the where clause
Red Gate Software's SQL Prompt 5 has a couple of new features that might be useful in this situation:
Column Dependencies: hover over a column name in a script and up pops a window containing a list of all the objects that use that column
Find Invalid Objects: show objects across the database that can't be used, often because they use columns that have been deleted
You can download a 14-day free trial to see if the tool would be useful for you.
Paul Stephenson
SQL Prompt Project Manager
Red Gate Software
You can use Dependence option for that table to find the Dependent object or list of Procedure or function which are depend on this table.
Use below script
sp_depends 'TableName'
another option is create script for that column containing but that will filter all the text in the procedure or function.
EDIT: sorry, my bad. here's the code for searching within the stored procedure's code
The following stored procedure should be able to list all the stored procedures whose text contain the desired string (so, place your column name in it and fire away):
CREATE PROCEDURE Find_Text_In_SP
#StringToSearch varchar(100)
AS
SET #StringToSearch = '%' +#StringToSearch + '%'
SELECT Distinct SO.Name
FROM sysobjects SO (NOLOCK)
INNER JOIN syscomments SC (NOLOCK) on SO.Id = SC.ID
AND SO.Type = 'P'
AND SC.Text LIKE #stringtosearch
ORDER BY SO.Name
GO
Usage:
exec Find_Text_In_SP 'desired_column_name'
Source here
If you use MS SQL later than version 2000, it's better to search sys.sql_modules rather than sys.syscomments, since syscomments only hold records of nvarchar(4000), and the text you are looking for may be split into two records.
So while you can use a query like this from MSDN
SELECT sm.object_id, OBJECT_NAME(sm.object_id) AS object_name, o.type, o.type_desc, sm.definition
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
WHERE sm.definition like '%' + #ColumnName + '%'
ORDER BY o.type;
you should be aware that this search finds any procedure containing that text, regardless of whether it is an actual column name and which table the column belongs to.

Stored procedures reverse engineering

We're having problem with a huge number of legacy stored procedures at work. Do you guys recommend any tool the can help better understand those procedures? Some kind of reverse engineering that indentifies inter-procedure dependencies and/or procedure vs. tables dependencies. Can be a free or commercial tool.
Thanks!
The cheaper solution than 'dependency tracker' is the data dictionary table sys.sql_dependencies which from which this data can be queried from the data dictionary. Oracle has a data dictionary view with similar functionality called DBA_DEPENDENCIES (plus equivalent USER_ and ALL_ views) . Using the other data dictionary tables (sys.tables/DBA_TABLES) etc. you can generate object dependency reports.
If you're feeling particularly keen you can use a recursive query (Oracle CONNECT BY or SQL Server Common Table Expressions) to build a complete object dependency graph.
Here's an example of a recursive CTE on sys.sql_dependencies. It will return an entry for every dependency with its depth. Items can occur more than once, possibly at different depths, for every dependency relationship. I don't have a working Oracle instance to hand to build a CONNECT BY query on DBA_DEPENDENCIES so anyone with edit privileges and the time and expertise is welcome to annotate or edit this answer.
Note also with sys.sql_dependencies that you can get column references from referenced_minor_id. This could be used (for example) to determine which columns were actually used in the ETL sprocs from a staging area with copies of the DB tables from the source with more columns than are actually used.
with dep_cte as (
select o2.object_id as parent_id
,o2.name as parent_name
,o1.object_id as child_id
,o1.name as child_name
,d.referenced_minor_id
,1 as hierarchy_level
from sys.sql_dependencies d
join sys.objects o1
on o1.object_id = d.referenced_major_id
join sys.objects o2
on o2.object_id = d.object_id
where d.referenced_minor_id in (0,1)
and not exists
(select 1
from sys.sql_dependencies d2
where d2.referenced_major_id = d.object_id)
union all
select o2.object_id as parent_id
,o2.name as parent_name
,o1.object_id as child_id
,o1.name as child_name
,d.referenced_minor_id
,d2.hierarchy_level + 1 as hierarchy_level
from sys.sql_dependencies d
join sys.objects o1
on o1.object_id = d.referenced_major_id
join sys.objects o2
on o2.object_id = d.object_id
join dep_cte d2
on d.object_id = d2.child_id
where d.referenced_minor_id in (0,1)
)
select *
from dep_cte
order by hierarchy_level
I've got this to open-up to the community now. Could someone with convenient access to a running Oracle instance post a CONNECT BY recursive query here? Note that this is SQL-server specific and the question owner has since made it clear that he's using Oracle. I don't have a running Oracle instance to hand to develop and test anything.
Redgate has a rather expensive product called SQL Dependency Tracker that seems to fulfill the requirements.
I think the Red Gate Dependency Tracker mentioned by rpetrich is a decent solution, it works well and Red Gate has 30 day trial (ideally long enough for you do do your forensics).
I would also consider isolating the system and running the SQL Profiler which will show you all the SQL action on the tables. This is often a good starting point for building a sequence diagram or however you choose to document these codes. Good luck!
Redgate SQL Doc. the generated documentation included cross-referenced dependency information. For example, for each table, it lists views, stored procedures, triggers etc that reference that table.
What database are the stored procedures in? Oracle, SQL Server, something else?
Edit based on comment: Given you're using Oracle then, have a look at TOAD. I use a feature in it called the Code Roadmap, which allows you to graphically display PL/SQL interdependancies within the database. It can run in Code Only mode, showing runtime call stack dependancies, or Code Plus Data mode, where it also shows you database objects (tables, views, triggers) that are touched by your code.
(Note - I am a TOAD user, and gain no benefit from referring it)
This isn't real deep or thorough, but I think that if you're using MS SQL Server or Oracle (Perhaps Nigel can help with a PL-SQL sample)...Nigel is on to something . This only goes 3 dependencies deep, but could be modified to go however deep you need. It's not the prettiest thing...but it's functional...
select
so.name + case when so.xtype='P' then ' (Stored Proc)' when so.xtype='U' then ' (Table)' when so.xtype='V' then ' (View)' else ' (Unknown)' end as EntityName,
so2.name + case when so2.xtype='P' then ' (Stored Proc)' when so2.xtype='U' then ' (Table)' when so2.xtype='V' then ' (View)' else ' (Unknown)' end as FirstDependancy,
so3.name + case when so3.xtype='P' then ' (Stored Proc)' when so3.xtype='U' then ' (Table)' when so3.xtype='V' then ' (View)' else ' (Unknown)' end as SecondDependancy,
so4.name + case when so4.xtype='P' then ' (Stored Proc)' when so4.xtype='U' then ' (Table)' when so4.xtype='V' then ' (View)' else ' (Unknown)' end as ThirdDependancy
from
sysdepends sd
inner join sysobjects as so on sd.id=so.id
left join sysobjects as so2 on sd.depid=so2.id
left join sysdepends as sd2 on so2.id=sd2.id and so2.xtype not in ('S','PK','D')
left join sysobjects as so3 on sd2.depid=so3.id and so3.xtype not in ('S','PK','D')
left join sysdepends as sd3 on so3.id=sd3.id and so3.xtype not in ('S','PK','D')
left join sysobjects as so4 on sd3.depid=so4.id and so4.xtype not in ('S','PK','D')
where so.xtype = 'P' and left(so.name,2)<>'dt'
group by so.name, so2.name, so3.name, so4.name, so.xtype, so2.xtype, so3.xtype, so4.xtype
How to find the dependency chain of a database object (MS SQL Server 2000(?)+)
by Jacob Sebastian
Every time he needs to deploy a new report or modify an existing
report, he needs to know what are the database objects that depend on
the given report stored procedure. Some times the reports are very
complex and each stored procedure might have dozens of dependent
objects and each dependent object may be depending on other dozens of
objects.
He needed a way to recursively find all the depending objects of a
given stored procedure. I wrote a recursive query using CTE to achieve
this.
The single best tool for reverse engineering is by APEX. Its amazing. It can even trace into .NET assemblies and tell you where the procs are used. Its by far the deepest product of its kind. RedGate has great other tools but not in this case.

Resources