How to Easily Log SQL Server 2008 Instance Level Metrics

If you want to record the results of some useful, instance level DMV queries somewhere where you can easily query them later, you can use this technique.  This gives you a pretty decent overview of the health of your instance by capturing AvgTaskCount, AvgRunnableTaskCount, AvgPendingIOCount, SQlServerCPUUtilization, and PageLifeExpectancy on a periodic basis.

I like to create a utility database called ServerMonitor on each one of my SQL instances. Then, I can use that database to hold instance level DMV queries wrapped in stored procedures. This way, I can ensure that the database is always available regardless of the mirroring status of other user databases on the instance.

The script below creates a table called SQLServerInstanceMetricHistory in that database. Then, after checking for SQL Server 2008 or greater and for Enterprise Edition, it enables Page compression on the clustered index for that table. Next, it creates a stored procedure called DBAdminRecordSQLServerMetrics that inserts rows into the SQLServerInstanceMetricHistory table. The next step would be to create a SQL Server Agent job that runs once a minute. The SQL Agent job would simply call this command:

EXEC dbo.DBAdminRecordSQLServerMetrics;

You could then query the SQLServerInstanceMetricHistory table to get a better idea of the average workload over time for that instance of SQL Server.

-- Logging SQL Server instance metrics
-- Glenn Berry 
-- March 2010
-- http://glennberrysqlperformance.spaces.live.com/
-- Twitter: GlennAlanBerry

-- Drop table if it exists
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = 
            OBJECT_ID(N'[dbo].[SQLServerInstanceMetricHistory]') 
            AND type in (N'U'))
DROP TABLE [dbo].[SQLServerInstanceMetricHistory]
GO


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- Create table to hold metrics
CREATE TABLE [dbo].[SQLServerInstanceMetricHistory]
(
    [SQLServerInstanceMetricHistoryID] [bigint] IDENTITY(1,1) NOT NULL,
    [MeasurementTime] [datetime] NOT NULL,
    [AvgTaskCount] [int] NOT NULL,
    [AvgRunnableTaskCount] [int] NOT NULL,
    [AvgPendingIOCount] [int] NOT NULL,
    [SQLServerCPUUtilization] [int] NOT NULL,
    [PageLifeExpectancy] [int] NOT NULL,
 CONSTRAINT [PK_SQLServerInstanceMetricHistory] PRIMARY KEY CLUSTERED 
(
    [SQLServerInstanceMetricHistoryID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
GO


-- Check for SQL Server 2008 or 2008 R2 and Enterprise Edition
IF LEFT(CONVERT(CHAR(2),SERVERPROPERTY('ProductVersion')), 2) = '10' 
   AND SERVERPROPERTY('EngineEdition') = 3
    BEGIN
        -- Use Page Compression on the clustered index 
        -- if we have SQL Server 2008 Enterprise Edition
        ALTER TABLE [dbo].[SQLServerInstanceMetricHistory] REBUILD PARTITION = ALL
        WITH (DATA_COMPRESSION = PAGE);
    END
GO


-- Drop stored procedure if it exists
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = 
            OBJECT_ID(N'[dbo].[DBAdminRecordSQLServerMetrics]') 
            AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[DBAdminRecordSQLServerMetrics]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

/* DBAdminRecordSQLServerMetrics ===================================================
Description : Used to keep track of instance level SQL Server Metrics
                        
Author: Glenn Berry    
Date: 3/9/2010    
Input:                            
Output:    
Used By: Only used to maintain the database                

Last Modified          Developer        Description
-------------------------------------------------------------------------------------
3/9/2010            Glenn Berry        Added Modification Comment
===================================================================================*/
CREATE PROCEDURE [dbo].[DBAdminRecordSQLServerMetrics]
AS

    SET NOCOUNT ON;
    SET QUOTED_IDENTIFIER ON;
    SET ANSI_NULLS ON;

    
    DECLARE @PageLifeExpectancy int = 0;
    DECLARE @SQLProcessUtilization int = 0;
    

    -- Get PLE info
    SET @PageLifeExpectancy = (SELECT cntr_value AS [PageLifeExpectancy]
    FROM sys.dm_os_performance_counters
    WHERE object_name = 'SQLServer:Buffer Manager'
    AND counter_name = 'Page life expectancy'); 
    
    
    -- Get CPU Utilization History (SQL 2008 Only)
    SET @SQLProcessUtilization = (SELECT TOP(1) SQLProcessUtilization AS [SQLServerProcessCPUUtilization]              
    FROM ( 
          SELECT record.value('(./Record/@id)[1]', 'int') AS record_id, 
                record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') 
                AS [SystemIdle], 
                record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 
                'int') 
                AS [SQLProcessUtilization], [timestamp] 
          FROM ( 
                SELECT [timestamp], CONVERT(xml, record) AS [record] 
                FROM sys.dm_os_ring_buffers 
                WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' 
                AND record LIKE '%<SystemHealth>%') AS x 
          ) AS y 
    ORDER BY record_id DESC);
    
    
    -- Add metrics info to SQLServerInstanceMetricHistory
    INSERT INTO dbo.SQLServerInstanceMetricHistory
    (MeasurementTime, AvgTaskCount, AvgRunnableTaskCount, AvgPendingIOCount, 
     SQLServerCPUUtilization, PageLifeExpectancy)
    (SELECT GETDATE() AS [MeasurementTime], AVG(current_tasks_count)AS [AvgTaskCount], 
            AVG(runnable_tasks_count) AS [AvgRunnableTaskCount], 
            AVG(pending_disk_io_count) AS [AvgPendingDiskIOCount], 
            @SQLProcessUtilization, @PageLifeExpectancy
     FROM sys.dm_os_schedulers
     WHERE scheduler_id < 255);
     
    RETURN;
    
GO






This entry was posted in SQL Server 2008. Bookmark the permalink.

4 Responses to How to Easily Log SQL Server 2008 Instance Level Metrics

  1. Steve says:

    How much data is once a minute? Do you trim this down over time?

  2. Glenn says:

    Very little data is collected every minute, its just one row, with pretty small columns. Plus, I use Page data compression on this table.

  3. Anthony says:

    Glen,

    I created a second step when I setup a job with your script in it, it ensures only a year of data will remain. While initially small, anyone with eventual space concerns wouldn’t have to think about it as the table can only get to a certain size.

    DELETE FROM [ServerMonitor].[dbo].[SQLServerInstanceMetricHistory]
    WHERE MeasurementTime < (DATEADD(DAY,-365,(select SYSDATETIME())) );

    Your SP works great for me, thank you for sharing!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s