Reputation: 179
I am trying to get top 5 (latest) of each sql job. I tried to query it like this
SELECT Pr1.job_ID,MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time) LastRun, COUNT(*) num
FROM MSDB.dbo.sysjobhistory Pr1
JOIN MSDB.dbo.sysjobhistory Pr2
ON MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time) = MSDB.dbo.Agent_datetime(Pr2.run_date, Pr2.run_time)
AND Pr1.job_ID = Pr2.job_ID
GROUP BY Pr1.job_ID, MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time)
HAVING COUNT (*) <= 5
ORDER BY job_ID, MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time)
But this query runs forever. I am using sql-server.
i also tried with a recommendation from below.
WITH CTE AS
(
SELECT jo.name,Pr1.job_ID, Pr1.run_date, Pr1.run_time,pr1.run_status,
Count(*) Over (Partition By Pr1.job_ID,Pr1.run_date,Pr1.run_time) As num,
Row_Number() Over (Partition By Pr1.job_ID,Pr1.run_date,Pr1.run_time
Order By pr1.run_date desc--, pr1.run_time desc
) As Rn
FROM MSDB.dbo.sysjobhistory Pr1
join MSDB.dbo.sysjobs jo on jo.job_id=pr1.job_id
JOIN MSDB.dbo.sysjobhistory Pr2
ON Pr1.job_ID = Pr2.job_ID --and pr1.run_status=pr2.run_status
and pr1.run_date >=pr2.run_date and pr1.run_time >=pr2.run_time
)
SELECT name,job_ID, run_date, run_time,run_status
FROM CTE
WHERE num <= 3 AND Rn = 1
Upvotes: 1
Views: 128
Reputation: 460228
It's running forever because you use the scalar valued function Agent_datetime
. If you use a query that doesn't need those functions the query optimizer can do it's job and use indexes.
You can simplify your task with window functions and a common-table-expression(CTE). Following groups by the column job_ID
and returns the latest record of each group according to the run_date
and run_time
columns:
WITH CTE AS
(
SELECT Pr1.job_ID, Pr1.run_date, Pr1.run_time,
Count(*) Over (Partition By Pr1.job_ID) As num,
Row_Number() Over (Partition By Pr1.job_ID
Order By Pr1.run_date DESC, Pr1.run_time DESC) As Rn
FROM MSDB.dbo.sysjobhistory
)
SELECT job_ID, run_date, run_time
FROM CTE
WHERE num <= 3 AND Rn = 1
Note that i've removed your pointless join condition and the self-join:
ON MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time)
= MSDB.dbo.Agent_datetime(Pr1.run_date, Pr1.run_time)
Upvotes: 1
Reputation: 1270513
Use row_number()
:
select pr.*
from (select pr.*,
row_number() over (partition by pr.job_id
order by pr.run_date desc, pr.run_time desc
) as seqnum
from MSDB.dbo.sysjobhistory pr
) pr
where seqnum <= 5;
Upvotes: 2