I am trying to track down all stored procedures in a database that have never been used, or that have not been used in many months.
I would like to find a query to s
DMVs will record stats for procedures, but they only possibly go as far back as the last restart (and often not that far, depending on how long a plan lives in cache):
SELECT * FROM sys.dm_exec_procedure_stats AS s
INNER JOIN sys.procedures AS p
ON s.[object_id] = p.[object_id]
ORDER BY p.name;
So if your system has only been up for a short time, this is not a reliable measure. The link @Siva points out is useful as well for some other ideas. Unfortunately SQL Server doesn't really track this for you overall so unless you add tracing or logging you are stuck with the trust you place in the DMV...
EDIT it was a good point, I was solving for the procedures that have run. Instead you may want this:
SELECT sc.name, p.name
FROM sys.procedures AS p
INNER JOIN sys.schemas AS sc
ON p.[schema_id] = sc.[schema_id]
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS st
ON p.[object_id] = st.[object_id]
WHERE st.[object_id] IS NULL
ORDER BY p.name;
Or you may want to also include procedures that have run as well, but order them by when they last ran:
SELECT sc.name, p.name
FROM sys.procedures AS p
INNER JOIN sys.schemas AS sc
ON p.[schema_id] = sc.[schema_id]
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS st
ON p.[object_id] = st.[object_id]
ORDER BY st.last_execution_time, p.name;
This will order first the procedures that haven't run since a restart, then the rest by when they were executed last, oldest first.
For some reason, my dm_exec_procedure_stats view clears itself out through the day. So I just ran it right now and the earliest execution times are from this morning, but I know we didn't restart SQL this morning or anything.
Anyway, I wanted to create a proc that I could put into a job to run every hour and capture which procs had run recently. Here is what I did:
Created a table to log the procs that get executed and their first and last execution times.
create table ProcsThatExecute (procName varchar(500), firstExecutionTime datetime, lastExecutionTime datetime)
Created a procedure that inserts or updates the ProcsThatExecute table. Run this every hour in a job and after a few days or weeks or months you have a log of which procs get used:
alter procedure LogProcsThatExecute as begin
--If they don't already exist in this table, add them.
insert into ProcsThatExecute(procName, firstExecutionTime, lastExecutionTime)
SELECT p.NAME ProcName, s.last_execution_time, null
FROM sys.procedures AS p
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
where not exists (
select 1 from ProcsThatExecute pte where pte.procName = p.name
) and last_execution_time is not null
--If they do exist in this table, update the last execution time.
update ProcsThatExecute set lastExecutionTime = s.last_execution_time
from ProcsThatExecute pte
inner join sys.procedures AS p on pte.procName = p.name
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
where s.last_execution_time is not null
end
Here's a variation on the accepted answer that was the most useful for me:
SELECT sc.NAME + '.' + p.NAME [Procedure]
,s.last_execution_time
FROM sys.procedures AS p
LEFT JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
INNER JOIN sys.schemas sc ON p.schema_id = sc.schema_id
ORDER BY s.last_execution_time
,sc.NAME
,p.NAME
The modifications display the last execution time and include the procedure's schema.