Learn more about SQL Server tools

mssqltips logo
 

Tutorials          DBA          Dev          BI          Career          Categories          Webcasts          Whitepapers          Today's Tip          Join

Tutorials      DBA      Dev      BI      Categories      Webcasts

DBA    Dev    BI    Categories

 

SSRS ReportServer Database Overview and Queries


By:   |   Last Updated: 2019-04-09   |   Comments (2)   |   Related Tips: > Reporting Services Administration

Problem

The SQL Server Reporting Services (SSRS) ReportServer database created during a native SSRS installation is undocumented by Microsoft, but I want to query it.

Solution

This tip will explain common tables and joins as found in a default ReportServer database and some example scenarios where such queries could be helpful.

Querying the SSRS Catalog

The first useful table within ReportServer is dbo.Catalog.  This table contains 1 row for every object found on the SSRS site.  This includes a row for each folder, report, data source, image, and linked report.  The primary key and clustered index for the table is ItemID and it is a GUID.  The user columns are also a GUID and can be converted to a name by joining to the dbo.Users table.

Depending on the version of SSRS not all type values may be available.

SELECT
  ItemID -- Unique Identifier
, [Path] --Path including object name
, [Name] --Just the objectd name
, ParentID --The ItemID of the folder in which it resides
, CASE [Type] --Type, an int which can be converted using this case statement.
    WHEN 1 THEN 'Folder'
    WHEN 2 THEN 'Report'
    WHEN 3 THEN 'File'
    WHEN 4 THEN 'Linked Report'
    WHEN 5 THEN 'Data Source'
    WHEN 6 THEN 'Report Model - Rare'
    WHEN 7 THEN 'Report Part - Rare'
    WHEN 8 THEN 'Shared Data Set - Rare'
    WHEN 9 THEN 'Image'
    ELSE CAST(Type as varchar(100))
  END AS TypeName
--, content
, LinkSourceID --If a linked report then this is the ItemID of the actual report.
, [Description] --This is the same information as can be found in the GUI
, [Hidden] --Is the object hidden on the screen or not
, CreatedBy.UserName CreatedBy
, CreationDate
, ModifiedBy.UserName ModifiedBy
, ModifiedDate
FROM 
  ReportServer.dbo.[Catalog] CTG
    INNER JOIN 
  ReportServer.dbo.Users CreatedBy ON CTG.CreatedByID = CreatedBy.UserID
    INNER JOIN
  ReportServer.dbo.Users ModifiedBy ON CTG.ModifiedByID = ModifiedBy.UserID;

Consider this instance of SSRS with one folder, one report, one linked report, and an image at the root.

The root folder contains one folder, one report, one linked report, and an image.

Within the folder is a single data source.

The contents of the folder from the root contains a data source object.

The output of the above query would contain a row for each item in the screenshots.  The row at the top with no ParentID is the root folder.  Notice that the root ItemID is the ParentID for each item stored at the root.  The one data source that lives in a folder outside the root has a ParentID value belonging to the source older.  Finally, the linked report is the only object with a LinkSourceID value and that that value is the ItemID of the report.

This query output shows how the ItemIDs are distributed as explained in the prior paragraph.

There is one additional column to cover within the catalog.  The column is called content.  This column is a binary value and contains the actual XML definition of the object where appropriate.  To view the actual XML rather than the binary value use this query.

This previous tip covers the content column in much more detail.

SELECT
  [Path]
, CASE [Type]
    WHEN 2 THEN 'Report'
    WHEN 5 THEN 'Data Source'    
  END AS TypeName
, CAST(CAST(content AS varbinary(max)) AS xml)
, [Description]
FROM ReportServer.dbo.[Catalog] CTG
WHERE
  [Type] IN (2, 5);

Continuing with the example from above, this is the expected output.  The blue text can be clicked and will open the XML in a new SSMS window.

This output looks similar to the previous result set except that there is a new column with blue hypertext that contains the definition of the object.

The Data Source object looks like this when expanded into its own window.

<DataSourceDefinition xmlns="http://schemas.microsoft.com/sqlserver/reporting/2006/03/reportdatasource">
  <Extension>SQL</Extension>
  <ConnectString>Server=.;Initial Catalog=ReportServer</ConnectString>
  <CredentialRetrieval>Integrated</CredentialRetrieval>
  <Enabled>True</Enabled>
</DataSourceDefinition>

Can one change these values, perhaps to move a report to a different folder or to hide/unhide it?  Technically, yes.  But that is not advised and would not be a supported operation.

Querying SSRS Report Execution Statistics

Every time an SSRS report executes a row is entered into the table dbo.ExecutionLog.  In modern versions of ReportServer the table is called dbo.ExecutionLogStorage and dbo.ExecutionLog is a view. 

SELECT * FROM dbo.ExecutionLog

The data returned by dbo.ExecutionLog can be difficult to understand so Microsoft did everyone a favor and started adding more views to make it even simpler to query.  They started with dbo.ExecutionLog2 and later dbo.ExecutionLog3.  Querying dbo.ExecutionLog3 shows many of the columns have been converted to human readable values.

SELECT
  [ItemPath] --Path of the report
, [UserName]  --Username that executed the report
, [RequestType] --Usually Interactive (user on the scree) or Subscription
, [Format] --RPL is the screen, could also indicate Excel, PDF, etc
, [TimeStart]--Start time of report request
, [TimeEnd] --Completion time of report request
, [TimeDataRetrieval] --Time spent running queries to obtain results
, [TimeProcessing] --Time spent preparing data in SSRS. Usually sorting and grouping.
, [TimeRendering] --Time rendering to screen
, [Source] --Live = query, Session = refreshed without rerunning the query, Cache = report snapshot
, [Status] --Self explanatory
, [RowCount] --Row count returned by a query
, [Parameters]
FROM ReportServer.dbo.ExecutionLog3

Here is some sample output from dbo.ExecutionLog3 after each report from the prior demo was executed once on the screen and then exported to Excel and PDF respectively.

The output shows 4 report executions, 2 each for 2 reports.  Each execution was successful.

One of the most useful parts of this table is the parameters column.  This column is part of the execution log and records the parameters used when a report was executed.  When a user says that they ran a report and received unexpected results it can be hard to replicate without knowing exactly what they typed in.  With this column the process becomes a matter of fact rather than a matter of guessing.  Did the user type in something unexpected?  Perhaps an obvious typo like the wrong year on their date range?  Bingo.  There it is in black and white.

The sample catalog report has been modified to accept 2 parameters.  They aren’t used by the report, but they will still be captured by the execution log.  Consider this execution of the catalog report.

The screenshot shows the value "MyTextEntry" for "MyParameter" and "3/13/2019" for StartDate.

The execution log captures these values like so.

The query results show "MyParameter=MyTextEntry&StartDate=3%2F13%2F2019%2012%3A00%3A00%20AM" for the Parameters column.

Querying SSRS Subscriptions

Anyone that manages an SSRS box has noticed that each subscription creates a SQL Server Agent Job with a GUID as its name.  These might seem like they don’t have meaning, but they actually do.  There are 2 new tables that will help understand how subscriptions are stored in the ReportServer database.

The table dbo.ReportSchedule is a list of schedules with which one might place a subscription.  Another table, dbo.Subscriptions marries a report from dbo.Catalog to a schedule in dbo.ReportSchedule creating a report subscription.  It is the unique identifier of dbo.ReportSchedule that becomes the name of the SQL Server Agent Job.  Once joined to msdb.dbo.sysjobs the subscription can be followed for history like any other job.

Continuing with the prior demo database a single subscription was created against My Catalog Report.

The SSRS GUI shows a single subscription created against the report "My Catalog Report"

As expected, a single new SQL Server Agent Job appeared on the instance.

A screenshot of the SQL Server Agent job list in SSMS shows a job with a GUID for a name.

This query will join from the catalog through to the agent job in MSDB.

SELECT
  ctg.[Path]
, s.[Description] SubScriptionDesc
, sj.[description] AgentJobDesc
, s.LastStatus
, s.DeliveryExtension
, s.[Parameters]
FROM
  ReportServer.dbo.[Catalog] ctg 
    INNER JOIN 
  ReportServer.dbo.Subscriptions s on s.Report_OID = ctg.ItemID
    INNER JOIN
  ReportServer.dbo.ReportSchedule rs on rs.SubscriptionID = s.SubscriptionID
    INNER JOIN
  msdb.dbo.sysjobs sj ON CAST(rs.ScheduleID AS sysname) = sj.name
ORDER BY
  rs.ScheduleID;

For this example, the results of this query show that the inner join has matched the subscription to the agent job.

There is one row in the result set with values from both ReportServer and MSDB indicating that the inner join found a match in both databases.

Using this Data in Real Life Scenarios

This information may be quite interesting to someone that enjoys SQL Server trivia, but its usefulness may seem limited.  This section of the tip includes a few real-life scenarios where this data was used to solve a business problem and may serve as an example of how this information can be applied to the day-to-day workings of a SQL Server professional.

This author remembers a time when a report was running slowly for the end users.  He was asked to help clean up the query to make the report run faster.  Upon reviewing the execution log, it was determined that the query (TimeDataRetrieval) was finishing in a sub-second time frame.  The rendering time (TimeRendering), however, was many seconds long.  This pushed the onus back to the report developer and away from the DBA who would have otherwise wasted time trying to tune a well-tuned query.

Another real-world scenario is a time that many users were complaining about application performance.  The SQL Server was running with higher than normal resource usage.  The SSRS application was consistently showing up with a busy, active SPID.  Reviewing dbo.ExecutionLog3 showed a query running repeatedly with very long TimeDataRetieval.  Reviewing history for days prior showed that execution was considerably longer today than yesterday or prior days.  Reviewing dbo.Catalog showed the report had been modified that very morning along with the user that modified it. It was clear which report writer needed to be consulted at that time to rollback a change and review it before resubmitting.

A customer was getting ready to migrate to a new SQL Server and wanted to clean up older reports that weren’t being used any longer.  Each business unit manager was presented with a report showing each report in their respective libraries along with the execution count and most recent execution time.  They were able to remove many more reports from the library than would have been had they not started with such concrete evidence that many reports were idle.

Next Steps


Last Updated: 2019-04-09


next webcast button


next tip button



About the author
MSSQLTips author Eric Blinn Eric Blinn is the Sr. Data Architect for Squire Patton Boggs. He is also a SQL author and PASS Local Group leader.

View all my tips




Post a comment or let the author know this tip helped.

All comments are reviewed, so stay on subject or we may delete your comment. Note: your email address is not published. Required fields are marked with an asterisk (*).

*Name    *Email    Email me updates 


Signup for our newsletter
 I agree by submitting my data to receive communications, account updates and/or special offers about SQL Server from MSSQLTips and/or its Sponsors. I have read the privacy statement and understand I may unsubscribe at any time.



    



Thursday, April 11, 2019 - 4:44:05 PM - Eric Blinn Back To Top

@Sureindran

Are you asking about the data set returned by a prior report execution?


Thursday, April 11, 2019 - 4:04:13 PM - Sureindran Nadesan Back To Top

Do you have a script that shows what's in the dataset?


Learn more about SQL Server tools