Our Microsoft SQL Server Reporting Services (SSRS) server was experiencing high load during certain times of the day. Here are the SQL queries that I used to chart concurrent subscription processes for analysis.
I wanted to plot a full 24 hours worth of report processing, and I wanted a row for each time an hourly subscription was run, so I created a table in memory to join on that had a row for each of the 24 hours.
I also wanted a metric that represented how much load each subscription put on the server, so I summed up each report’s data retrieval time, processing time, and rendering time for the entire history of data.
I also wanted the report start and average end time, so I used an average of the difference between the start and end times of the report for the entire history of data to get an average runtime.
DECLARE @myCounter int SET @myCounter = 0 DECLARE @myTable TABLE (myType int, myHour int) DECLARE @myTable2 TABLE (starttime varchar(8), endtime varchar(8)) DECLARE @results TABLE (myTime varchar(8), myCount int) WHILE (@myCounter < 24) BEGIN INSERT INTO @myTable SELECT 2, @myCounter SET @myCounter = @myCounter + 1 END INSERT INTO @myTable SELECT 4, 0 SELECT a.Name , a.Path , f.weight , CONVERT(varchar, DATEADD(hour, e.myHour, d.StartDate), 8) AS starttime , CONVERT(varchar, DATEADD(minute, f.avgruntime + 1, DATEADD(hour, e.myHour, d.StartDate)), 8) AS endtime FROM ReportServer.dbo.Catalog a JOIN ReportServer.dbo.Subscriptions b ON(a.ItemID=b.Report_OID) JOIN ReportServer.dbo.ReportSchedule c ON(a.ItemID=c.ReportID AND b.SubscriptionID=c.SubscriptionID) JOIN ReportServer.dbo.Schedule d ON(c.ScheduleID=d.ScheduleID) JOIN @myTable e ON(d.RecurrenceType=e.myType) JOIN (SELECT ReportID , AVG(DATEDIFF(minute, TimeStart, TimeEnd)) AS avgruntime , SUM(CAST(TimeDataRetrieval AS bigint) + CAST(TimeProcessing AS bigint) + CAST(TimeRendering AS bigint)) AS weight FROM ReportServer.dbo.ExecutionLogStorage GROUP BY ReportID ) f ON(a.ItemID=f.ReportID) WHERE d.RecurrenceType IN (2,4) ORDER BY f.weight DESC, starttime, endtime;
This gave me a good list of reports that I should look into.
Name | Path | weight | starttime | endtime |
---|---|---|---|---|
Report 1 | /RSX/Report 1 | 1855511629 | 06:00:00 | 06:10:00 |
Report 1 | /RSX/Report 1 | 1855511629 | 08:00:00 | 08:10:00 |
Report 2 | /RSX/Report 2 | 128975417 | 03:00:00 | 03:14:00 |
Report 2 | /RSX/Report 2 | 128975417 | 07:00:00 | 07:14:00 |
Report 3 | /Travel/Report 1 | 92511205 | 07:00:00 | 07:02:00 |
... |
Next, I really wanted a timeline chart that showed the start and end times of reports so that I could see how the runtimes overlapped, so that we could see if performance could be improved by pacing the subscriptions better.
To do this, I needed to create another in memory table in order to build a map of every minute for the 24 hour period of time. Once I had that table, it required just one more minor addition to the query to generate the chart data.
DECLARE @myCounter int SET @myCounter = 0 DECLARE @myTable TABLE (myType int, myHour int) DECLARE @myTable2 TABLE (starttime varchar(8), endtime varchar(8)) DECLARE @results TABLE (myTime varchar(8), myCount int) WHILE (@myCounter < 24) BEGIN INSERT INTO @myTable SELECT 2, @myCounter SET @myCounter = @myCounter + 1 END INSERT INTO @myTable SELECT 4, 0 INSERT INTO @myTable2 SELECT CONVERT(varchar, DATEADD(hour, e.myHour, d.StartDate), 8) AS starttime , CONVERT(varchar, DATEADD(minute, f.avgruntime + 1, DATEADD(hour, e.myHour, d.StartDate)), 8) AS endtime FROM ReportServer.dbo.Catalog a JOIN ReportServer.dbo.Subscriptions b ON(a.ItemID=b.Report_OID) JOIN ReportServer.dbo.ReportSchedule c ON(a.ItemID=c.ReportID AND b.SubscriptionID=c.SubscriptionID) JOIN ReportServer.dbo.Schedule d ON(c.ScheduleID=d.ScheduleID) JOIN @myTable e ON(d.RecurrenceType=e.myType) JOIN (SELECT ReportID , AVG(DATEDIFF(minute, TimeStart, TimeEnd)) AS avgruntime , SUM(TimeDataRetrieval + TimeProcessing + TimeRendering) AS weight FROM ReportServer.dbo.ExecutionLogStorage GROUP BY ReportID ) f ON(a.ItemID=f.ReportID) WHERE d.RecurrenceType IN (2,4) DECLARE @myHour int DECLARE @myMin int SET @myHour = 0 SET @myMin = 0 WHILE (@myHour < 24) BEGIN WHILE (@myMin < 60) BEGIN INSERT INTO @results SELECT RIGHT('0' + CAST(@myHour AS varchar(2)),2) + ':' + RIGHT('0' + CAST(@myMin AS varchar(2)),2) + ':00' AS myTime , COUNT(*) FROM @myTable2 WHERE starttime <= RIGHT('0' + CAST(@myHour AS varchar(2)),2) + ':' + RIGHT('0' + CAST(@myMin AS varchar(2)),2) + ':00' AND endtime >= RIGHT('0' + CAST(@myHour AS varchar(2)),2) + ':' + RIGHT('0' + CAST(@myMin AS varchar(2)),2) + ':00' SET @myMin = @myMin + 1 END SET @myHour = @myHour + 1 SET @myMin = 0 END SELECT * FROM @results;
This is the chart that I created in Excel using this data, although one could easily turn this into a daily SSRS report.
This chart allowed me to see where the problem areas were and pace out the report subscriptions better.