Querying Perfmon data from SQL

In a previous post I talked about Relogging Perfmon binary log files to SQL. The next obvious step is to query the data from the database.

There are two ways to do this:

  1. Use Perfmon itself to connect to the SQL data source
  2. Use another tool to query the SQL data source directly

1. Using Performance Monitor

Once you open Performance Monitor, press the View Log Data button (Ctrl-L):

image

Then on the Source tab, if you have the ODBC System DSN configured to connect to your performance database, it will show up.

image

This allows you to view the log files directly from SQL, just as if you had loaded the binary log files.

2. Querying SQL directly

At first glance, the schema doesn’t seem very intuitive. But with a little digging, it’s not too bad.

image

Whenever you use PerfMon or relog to log to a database, it automatically sets up this schema for you. There are three tables:

  1. DisplayToID – This lists all the log sets that are in the database
  2. CounterData – This is where the actual counter values are stored
  3. CounterDetails – This is where the metadata about each counter / object / instance is stored

Here are some queries that I’ve found useful:

Get all computers that have counter data logged:

SELECT DISTINCT MachineName
FROM CounterDetails
ORDER BY MachineName

Get available object names for a particular computer:

SELECT DISTINCT ObjectName
FROM CounterDetails
WHERE MachineName = ‘\\MYSERVER’
ORDER BY ObjectName

Get counter names for a particular computer and object:

SELECT DISTINCT CounterName
FROM CounterDetails
WHERE MachineName = ‘\\MYSERVER’
AND ObjectName = ‘Processor’
ORDER BY CounterName

Get instance names for a particular computer, object and counter:

SELECT DISTINCT InstanceName
FROM CounterDetails
WHERE MachineName = ‘\\MYSERVER’
AND ObjectName = ‘Processor’
AND CounterName = ‘% Processor Time’
ORDER BY InstanceName

Get counter values for a particular computer, object, counter and instance. Name the column appropriately:

SELECT
    CAST(LEFT(CounterDateTime, 16) as smalldatetime) AS CounterDateTime,
    REPLACE(CounterDetails.MachineName,'\\','') AS ComputerName,
    CounterDetails.ObjectName + ISNULL('(' + CounterDetails.InstanceName + ')','') + '\' + CounterDetails.CounterName AS [Counter],
    CounterData.CounterValue
FROM CounterData
    INNER JOIN CounterDetails ON CounterData.CounterID = CounterDetails.CounterID
    INNER JOIN DisplayToID ON CounterData.GUID = DisplayToID.GUID
WHERE CounterDetails.ObjectName = 'Processor'
    AND    CounterDetails.CounterName = '% Processor Time'
    AND    CounterDetails.MachineName = '\\MYSERVER’
    AND CounterDetails.InstanceName = '_Total'
ORDER BY CounterData.CounterDateTime

There’s a few nuances in the schema which creates complexity in this query. Let me try and explain:

  • CounterDateTime is a char(24) instead of a datetime. By trimming it to 16 characters, this allows it to be converted to a smalldatetime at the ‘minutes’ resolution – not seconds.
  • MachineName includes ‘\\’, we want to trim it to make it look pretty.
  • InstanceName can be null. An example is the Memory\Pages/sec object & counter. The instance value for this combination is null. So we only show the instance name if it’s not null.

Of course now that you have the data being collected, post-processed and queryable in SQL – the next logical step is to make it reportable. Here is a report that I’ve built to display this data. I’ll talk about it more in a future blog post.

PerfMon SQL Report

Published 07 November 08 04:41 by grantholliday

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# jeffr said on December 31, 2008 3:42 PM:

Great stuff, Grant! I would be interested in learning more about how you used the Interval report parameter in your example.

# grantholliday said on January 2, 2009 12:15 PM:

Hi JeffR,

I used a MOD (%) function with the @Interval parameter to filter the number of data points.

AND DATEPART(MINUTE, CAST(LEFT(CounterDateTime, 16) as smalldatetime)) % @Interval = 0

So if you set the @Interval to '60', it will only return every 60th value. And since we know that the data is logged once per minute, that is equivalent to one data point an hour. 15 = every 15 minutes, etc.

I've made some modifications to the sprocs + reports lately as well which I'll share soon.

# Richard said on January 24, 2009 12:38 AM:

Grant,

Nice work. When are you doing the follow up. I would like to see how you developed the reports.

Thans

Rich

# Charlie said on January 31, 2009 1:54 AM:

Grant - Excellent stuff...I've been looking for a MSFT article of perfmon report from SQL for sometime.  Please do let us know more soon, including more about the report builder you're using in the screenshot at the end of the article.  Is that part of Windows Server 2008?  Cheers!

# granth's blog said on May 21, 2009 1:27 PM:

Since joining Microsoft, I’ve become intimately familiar with running a TFS server for ~3,500 users in

# Kenny Evitt said on May 30, 2009 6:01 PM:

This will work to convert 'CounterDateTime' to a datetime:

CONVERT(datetime, LEFT(CounterDateTime, 23), 121)

For some reason, the right-most character is the null character.

# Jay said on June 9, 2009 1:47 PM:

Is there anyway you can post your report? It looks great and I'm not sure how to duplicate it.

# Jonno said on June 12, 2009 4:39 AM:

Yeah that look great! I would love to get my hands on those reports!

# Paulie said on July 30, 2009 8:31 AM:

Great article. I too am looking forward to your next one showing how you create the reports.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker