Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
154409 stories
·
33 followers

Using ExecutionLog views in SQL Server Reporting Services to monitor performance

1 Share

After upgrading our SQL Server Reporting Services (SSRS) environment, we noticed some isuses: reports were slow, users were complaining, and we had no idea where to start. The good news is that SSRS has been quietly collecting detailed execution data the whole time — and a set of built-in views makes it surprisingly easy to query.

This post walks through the ExecutionLog views, what they contain, and how to turn that data into actionable performance insights.

What are the ExecutionLog views?

SSRS logs every report execution to the ReportServer database. Three views expose this data at different levels of detail:

  • ExecutionLog — A simple view covering the basics: report name, user, start time, and duration. Good for quick lookups.
  • ExecutionLog2 — Adds AdditionalInfo, an XML column with richer metadata such as estimated row counts and data source connection details.
  • ExecutionLog3 — The most complete view. Breaks execution time into three distinct phases — TimeDataRetrieval, TimeProcessing, and TimeRendering — which is where the real diagnostic power lies.

For most performance work, ExecutionLog3 is the one you want.

Understanding the key columns

Before diving into queries, it helps to know what you're working with in ExecutionLog3:

Column Description
ReportPath The full path to the report on the server
UserName The account that ran the report
RequestType Interactive (user-initiated) or Subscription
Format Output format: HTML4.0, PDF, EXCEL, etc.
TimeStart / TimeEnd Wall-clock start and end of execution
TimeDataRetrieval Milliseconds spent fetching data from sources
TimeProcessing MMilliseconds spent processing/aggregating data
TimeRendering Milliseconds spent rendering the output format
Status rsSuccess, rsProcessingAborted, or an error code
RowCount Number of rows returned by the primary dataset
ByteCount Size of the rendered output in bytes
Source Whether the result came from Live, Cache, or Snapshot

The time breakdown is the most valuable part. A report with high TimeDataRetrieval probably needs query tuning or indexing. High TimeProcessing suggests complex expressions or large datasets being crunched in SSRS itself. High TimeRendering often points to reports with too many elements, sub-reports, or large images.

Useful queries to get started

1. Find your slowest reports

SELECT
    ReportPath,
    COUNT(*)                            AS ExecutionCount,
    AVG(TimeDataRetrieval)              AS AvgDataRetrieval_ms,
    AVG(TimeProcessing)                 AS AvgProcessing_ms,
    AVG(TimeRendering)                  AS AvgRendering_ms,
    AVG(TimeDataRetrieval
        + TimeProcessing
        + TimeRendering)                AS AvgTotal_ms,
    MAX(TimeDataRetrieval
        + TimeProcessing
        + TimeRendering)                AS MaxTotal_ms
FROM ExecutionLog3
WHERE TimeStart >= DATEADD(day, -30, GETDATE())
  AND Status = 'rsSuccess'
GROUP BY ReportPath
ORDER BY AvgTotal_ms DESC;

This gives you a ranked list of your worst performers over the past 30 days. Focus on reports that combine high average time and high execution count — those have the most impact on your environment.

2. Diagnose where time is being spent

SELECT
    ReportPath,
    AVG(TimeDataRetrieval)  AS AvgData_ms,
    AVG(TimeProcessing)     AS AvgProcessing_ms,
    AVG(TimeRendering)      AS AvgRendering_ms,
    AVG(TimeDataRetrieval) * 100.0
        / NULLIF(AVG(TimeDataRetrieval + TimeProcessing + TimeRendering), 0)
                            AS PctData,
    AVG(TimeProcessing) * 100.0
        / NULLIF(AVG(TimeDataRetrieval + TimeProcessing + TimeRendering), 0)
                            AS PctProcessing,
    AVG(TimeRendering) * 100.0
        / NULLIF(AVG(TimeDataRetrieval + TimeProcessing + TimeRendering), 0)
                            AS PctRendering
FROM ExecutionLog3
WHERE TimeStart >= DATEADD(day, -7, GETDATE())
  AND Status = 'rsSuccess'
GROUP BY ReportPath
HAVING AVG(TimeDataRetrieval + TimeProcessing + TimeRendering) > 5000
ORDER BY AVG(TimeDataRetrieval + TimeProcessing + TimeRendering) DESC;

The percentage columns immediately show you where to focus. If 85% of execution time is data retrieval, start with the underlying queries — not the report layout.

3. Spot failed executions

SELECT
    ReportPath,
    Status,
    COUNT(*) AS FailureCount,
    MAX(TimeStart) AS MostRecent
FROM ExecutionLog3
WHERE TimeStart >= DATEADD(day, -7, GETDATE())
  AND Status <> 'rsSuccess'
GROUP BY ReportPath, Status
ORDER BY FailureCount DESC;

Failures that users never report are surprisingly common. This query surfaces them.

4. Identify peak usage times

SELECT
    DATEPART(hour, TimeStart)   AS HourOfDay,
    DATEPART(weekday, TimeStart) AS DayOfWeek,
    COUNT(*)                    AS ExecutionCount,
    AVG(TimeDataRetrieval
        + TimeProcessing
        + TimeRendering)        AS AvgTotal_ms
FROM ExecutionLog3
WHERE TimeStart >= DATEADD(day, -30, GETDATE())
GROUP BY DATEPART(hour, TimeStart), DATEPART(weekday, TimeStart)
ORDER BY DayOfWeek, HourOfDay;

Knowing when your environment is under the most load helps you schedule subscriptions more intelligently and plan maintenance windows.

5. Check cache effectiveness

SELECT
    ReportPath,
    Source,
    COUNT(*) AS ExecutionCount
FROM ExecutionLog3
WHERE TimeStart >= DATEADD(day, -7, GETDATE())
GROUP BY ReportPath, Source
ORDER BY ReportPath, Source;

If a frequently-run report shows Live for nearly every execution, it's a strong candidate for caching or snapshots. Reports served from Cache are dramatically faster for end users and lighter on your data sources.

Practical tips

Mind the log retention. By default, SSRS keeps 60 days of execution history. You can change this in Report Server Configuration Manager, or schedule a job to archive data to a separate table before it rolls off.

Watch for parameter-driven outliers. A report might average 3 seconds but occasionally spike to 45 seconds because someone runs it with a 5-year date range. Look at your MAX values alongside averages, and consider adding parameter validation to the report itself.

Combine with subscription data. Subscriptions that run at 6am and take 20 minutes may be blocking interactive users who arrive at 6:30. Knowing both patterns lets you schedule more thoughtfully.

Look at RowCount alongside time. A report returning 500,000 rows into an Excel export isn't necessarily broken — but it might be a sign a user is working around a missing feature elsewhere in your system.

Don't ignore ByteCount. Very large rendered outputs (say, multi-MB PDFs generated repeatedly) can quietly stress your network and storage. Flag these for review with the report owners.

Wrapping up

I'm happy to see that Microsoft integrated telemetry out-of-the-box. The ExecutionLog views require no configuration, no agents, and no third-party tools — the data is already there, waiting to be queried. Starting with ExecutionLog3 and a handful of the queries above, you can move from reactive firefighting to proactive performance management in an afternoon.

Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

A hypothetical redesign of System.Diagnostics.Process to avoid confusion over properties that are valid only when you are the one who called Start

1 Share

Some time ago, I noted that the Process.Standard­Output property is an attractive nuisance because it is valid only on Process objects that you called Start on. You can’t just grab any old Process object and try to access its standard handles.

Others in the comments had their ideas on how to remove the confusion. Here’s mine. The principle is that the properties and methods of the Process object should be valid for all instances of the Process class. If a property or method is valid only conditionally, then either move it to a place that is accessible only if the condition is met, or get rid of it entirely if it adds no value.

The standard handles are the three properties that make sense only for Process objects that were created by the static Start method. There are also four methods related to those standard handles, as well as two events. Move them all to a new class, call it Process­Start­Result:

class ProcessStartResult
{
    public Process Process { get; }
    public System.IO.StreamWriter StandardInput { get; }
    public System.IO.StreamWriter StandardOutput { get; }
    public System.IO.StreamWriter StandardError { get; }

    public void BeginOutputReadLine();
    public void CancelOutputReadLine();
    public event DataReceivedEventHandler? OutputDataReceived;

    public void BeginErrorReadLine();
    public void CancelErrorReadLine();
    public event DataReceivedEventHandler? ErrorDataReceived;
}

Change the signature of all the overloads of the Start method so that they return a Process­Start­Result instead of a Process. Now it is impossible to do anything with the standard handles from a process you didn’t start: If you didn’t start the process, then you don’t have a Process­Start­Result. This removes the confusion that existed in the original attempt to have a process read from its own standard output.

This follows a principle I wrote about earlier: To force the developer to do things in a certain order, make the second step dependent on something produced by the first step. In this case, we want to force the developer to call Start before they use the standard handles, so we put the members related to the standard handles on a thing that you can obtain only by calling Start.

Next, remove the Start­Info property entirely. It serves two purposes:

  • Prior to calling the Start method, it provides a convenient pre-made Process­Start­Info.
  • After calling the Start method, it holds a copy of the parameters that you passed to the Start method.

The first purpose is just to cover for people who are too lazy to write the new keyword. So don’t be lazy. Write new Process­Start­Info().

The second purpose doesn’t tell you anything you don’t already know, since you are the one who passed the parameters to the Start method in the first place. If they are so important to you, you can save them yourself.

Removing the Start­Info avoids confusion over whether the properties in it describe the process you want to start, or whether they describe a process that has already started. (And often, it describes neither!)

I think that takes care of the largest source of confusion over the proper use of the Process class.

The post A hypothetical redesign of <CODE>System.<WBR>Diagnostics.<WBR>Process</CODE> to avoid confusion over properties that are valid only when you are the one who called <CODE>Start</CODE> appeared first on The Old New Thing.

Read the whole story
alvinashcraft
14 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

New tune for Code.org’s Hadi Partovi: CEO of piano education venture with unique method and big ambitions

1 Share
Hadi Partovi, founder of Code.org and new CEO of Payam Music, speaking at a Microsoft event in July 2025. (GeekWire Photo / Todd Bishop)

Hadi Partovi helped kids around the world learn to code. Next on the playlist: piano.

The Code.org founder, who earlier this year handed off the CEO role at the nonprofit, announced this weekend that he is the new CEO of Payam Music, a Bothell, Wash.-based piano school that he plans to expand nationally with backing from Mark Cuban, Uber CEO Dara Khosrowshahi (Partovi’s cousin), and Oscar-winning composer Hans Zimmer.

The news coincides with a 60 Minutes segment and a USA Today feature about the school and its teaching approach, known as the Payam Method. Instead of starting with sheet music and a classical repertoire, students learn to play using letters and numbers, choosing songs they already love. Traditional notation and theory come later as students progress through 18 levels.

“I’m taking my experience teaching computer science to hundreds of millions and connecting it to my lifelong love of piano,” Partovi wrote in a LinkedIn post on Sunday.

Partovi told USA Today that he and his twin brother Ali learned piano as children in Iran after the Islamic revolution, when the family was stuck at home. Their father cut out musical notes and taped them to the keys so they could teach themselves. 

After immigrating to the U.S. and moving in with their grandmother, Partovi could no longer afford lessons but kept playing on his own. He still composes his own music.

Payam Music was founded by Payam Khastkhodaei, a 32-year-old piano teacher who developed the method while giving lessons out of a converted home in Bothell. Partovi discovered the school when his son Darius enrolled and saw rapid progress after years of struggling with traditional lessons.

On 60 Minutes, Partovi compared the approach to Code.org’s method of teaching coding with blocks and drag-and-drop elements instead of ones and zeros and semicolons.

Payam Music has eight locations, in Washington state, California, New York, and Maryland. It has raised seed funding in the single-digit millions to expand nationally, USA Today reported.

Khastkhodaei told paper that about 97% of his students continue beyond the first year, compared with 15% to 20% in traditional instruction. Lessons cost $75 to $100 per session.

Read the whole story
alvinashcraft
9 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Ferrari reveals its first EV, with design help from Jony Ive

1 Comment and 2 Shares
An image of a blue Ferrari with a minimalist design and black accents.
The Ferrari Luce will start at €550,000 in Italy, but US pricing hasn’t been announced. | Image: Ferrari

After months of teasers, Ferrari is offering the first full view of its Luce electric vehicle. The Luce is notable not just for being Ferrari's first EV, but for being designed in collaboration with Jony Ive and Mark Newson at their collective LoveFrom. It's also going to be Ferrari's second four-door car and its first five-seat one.

We already knew Ive and Newson were working on the Luce's interiors, which were shown off earlier this year. Now Ferrari says LoveFrom was allowed to "define the design direction of the project from the outset," inside and out.

Tim Stevens reporting for Engadget offers a few firsthand impression …

Read the full story at The Verge.

Read the whole story
alvinashcraft
9 hours ago
reply
Pennsylvania, USA
Share this story
Delete
1 public comment
jgbishop
8 hours ago
reply
This thing is *ugly*...
Raleigh, NC

Paint.NET 5.2 Alpha (build 9641)

1 Share

This is an updated alpha build for 5.2 that fixes a handful of issues and crashes.

You can read more about 5.2 and what it includes by reading the release notes for the first alpha.

Change Log

Changes since 5.2 Alpha (build 9625):

  • The selection will no longer be tinted when opening an effect or adjustment.
  • Improved the latency of the brush tool “preview cursor” by 1 frame.
  • Added some extra digits past the decimal place for the zoom level in the status bar.
  • Shortened the length of the animations used when closing an image or deleting a layer.
  • Fixed Edit -> Paste into New Image not setting the color profile, resulting in it always being sRGB.
  • Fixed a rare crash with the brush tools when adjusting the brush size. This crash could only be reproduced with external automation (e.g. macro record/playback with AutoHotKey).
  • Fixed copy/paste sometimes adding an extra row or column of pixels around the edge of the image due to bad rounding after floating point precision drift.
  • Fixed a crash when pasting images that are CMYK, or which have a LUT-based color profile, or a mismatched color profile (e.g. CMYK profile on RGB image).
  • Fixed some issues with copy/paste of indexed (e.g. 8-bit palettized) images.
  • Fixed not being able to use new Effect plugins compiled against the 5.2 Alpha (build 9625) binaries.
  • Changed the package ZIPs so that they use forward slashes instead of backslashes, which simplifies working with these outside of Windows (e.g. for WINE porting effort).

Download and Install

This build is available via the built-in updater as long as you have opted-in to pre-release updates. From within Settings -> Updates, enable “Also check for pre-release (beta) versions of paint.net” and then click on the Check Now button. You can also use the links below to download an offline installer or portable ZIP.

You can also download the installer here (for any supported CPU and OS), which is also where you can find downloads for offline installers, portable ZIPs, and deployable MSIs.



Read the whole story
alvinashcraft
9 hours ago
reply
Pennsylvania, USA
Share this story
Delete

PowerSchool’s $17.25 Million Settlement Exposes Years of Student Data Tracking

1 Share
If you ask most people what breach PowerSchool experienced, their first response might be the 2024 hacking incident that affected tens of millions of students. But even before that breach, there was another significant breach involving PowerSchool that began in 2021. Colin Lee and Koji Edmunds report: In early April, many students across the world...

Source

Read the whole story
alvinashcraft
9 hours ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories