collecting performance data for SQL Server via Powershell
Performance Monitor is a Windowds-based tool which has also very effective counters for SQL Server. There are various methods to collect performance data like typeperf (http://technet.microsoft.com/en-us/library/bb490960.aspx)
and creating data collector sets (http://technet.microsoft.com/en-us/library/cc722414.aspx). Another method is using Powershell script. Here you go with the script:
#In do-while loop, you can define how many times you would like to run the script with one execution. <br> #Get-Counter cmdlet has -max samples parameter as well, however if you set it a value other than 1 then<br> #it waits until the end of the script to write the database after collecting all samples.<br> #With the logic of do-while loop I managed to write the database after each sample collection.<br> $a = 0 <br> do<br> {<br> #$server variable defines the server to be monitored<br> #if you would like to monitor more than 1 server you can use Get-Content cmdlet as shown below:<br> #$server = @(get-content "C:\perfcounter_ps\AllServers.txt")<br> $server = 'ISILEFE03'<br> #$monitorServer variable defines the server that we are collecting data on and $monitorDB variable defines<br> #the database that we are using like a datawarehouse<br> $monitorServer = "ISILEFE03" <br> $monitorDB = "testperf" <br> $counters = @("\Memory\Available MBytes",<br> "\Memory\Pages/sec",<br> "\PhysicalDisk(_Total)\Avg. Disk sec/Read",<br> "\PhysicalDisk(_Total)\Avg. Disk sec/Write",<br> "\PhysicalDisk(_Total)\Current Disk Queue Length",<br> "\PhysicalDisk(*)\Avg. Disk sec/Read",<br> "\PhysicalDisk(*)\Avg. Disk sec/Write",<br> "\PhysicalDisk(*)\Current Disk Queue Length",<br> "\Process(sqlservr)\% Privileged Time",<br> "\Process(sqlservr)\% Processor Time",<br> "\Processor(_Total)\% Privileged Time",<br> "\Processor(_Total)\% Processor Time",<br> "\SQLServer:Buffer Manager\Buffer cache hit ratio",<br> "\SQLServer:Buffer Manager\Lazy writes/sec",<br> "\SQLServer:Buffer Manager\Page life expectancy",<br> "\SQLSERVER:Memory Manager\Memory Grants Pending" ,<br> "\SQLServer:SQL Statistics\Batch Requests/sec",<br> "\System\Context Switches/sec",<br> "\System\Processor Queue Length" <br> ) <br> $sequence=1 <br> $collections = Get-Counter -ComputerName $server -Counter $counters -SampleInterval 10 -MaxSamples 1<br> Write-Output $collections <br> foreach ($collection in $collections) <br> {$sampling = $collection.CounterSamples | Select-Object -Property TimeStamp, Path, Cookedvalue <br> $xmlString = $sampling | ConvertTo-Xml -As String<br> #dbo.usp_InserPerfmonCounter is the stored procedure that is used to insert collected data to testperf database<br> $query = "dbo.usp_InsertPerfmonCounter '$xmlString';" <br> Invoke-Sqlcmd -ServerInstance $monitorServer -Database $monitorDB -Query $query<br> Write-Output $sampling<br> $sequence+=1}<br> #Write-Output $sampling <br> #Write-Output $xmlString <br> #Write-Output $query <br> $a+=1<br> Write-Output $a<br> }<br> while($a-lt 10)
The script for the stored procedure dbo.usp_InsertPerfmonCounter is:
(refering http://www.travisgan.com/2013/03/powershell-and-performance-monitor.html)
USE [testperf]
GO
/****** Object: StoredProcedure [dbo].[usp_InsertPerfmonCounter] Script Date: 11/5/2013 11:27:48 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_InsertPerfmonCounter]
(
@xmlString varchar(max)
)
AS
SET NOCOUNT ON;
DECLARE @xml xml;
SET @xml = @xmlString;
INSERT INTO [dbo].[PerfmonCounterData] ([TimeStamp], [Server], [CounterGroup], [CounterName], [CounterValue])
SELECT [Timestamp]
, SUBSTRING([Path], 3, CHARINDEX('\',[Path],3)-3) AS [Server]
, SUBSTRING([Path]
, CHARINDEX('\',[Path],3)+1
, LEN([Path]) - CHARINDEX('\',REVERSE([Path]))+1 - (CHARINDEX('\',[Path],3)+1)) AS [CounterGroup]
, REVERSE(LEFT(REVERSE([Path]), CHARINDEX('\', REVERSE([Path]))-1)) AS [CounterName]
, CAST([CookedValue] AS float) AS [CookedValue]
FROM
(SELECT
[property].value('(./text())[1]', 'VARCHAR(200)') AS [Value]
, [property].value('@Name', 'VARCHAR(30)') AS [Attribute]
, DENSE_RANK() OVER (ORDER BY [object]) AS [Sampling]
FROM @xml.nodes('Objects/Object') AS mn ([object])
CROSS APPLY mn.object.nodes('./Property') AS pn (property)) AS bp
PIVOT (MAX(value) FOR Attribute IN ([Timestamp], [Path], [CookedValue]) ) AS ap;
GO
And here is the script of the table that I used.
CREATE TABLE [dbo].[PerfmonCounterData]
(
[ID] [bigint] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
[Server] [nvarchar](50) NOT NULL,
[TimeStamp] [datetime2](0) NOT NULL,
[CounterGroup] [varchar](200) NULL,
[CounterName] [varchar](200) NOT NULL,
[CounterValue] [decimal](18, 5) NULL
);
GO
And then when we run my script with the command below on Powershell, we can check the result from our table
for inserted data.The result is written for every 10 sec as we expected since sampleinterval parameter is 10 sec
for Get-Counter cmdlet. And with the help of do-while loop, the data is written 10 times with every execution of
the script. It means that the execution of the script takes 100+ seconds.
cd "C:\perfcounter_ps"<br>powershell.exe .\collectperfdata.ps1
And here is our last step, scheduling a SQL Server agent job to run periodically, The only thing you
should take into consideration is just changing the type as Powershell. After this point, you can just send
queries filtering according to counter or timestamp, even you can visualize your data on Reporting Services.
BE CAREFUL that i am using SQL Server 2012, and it is enough when I import sql powershell module
once to be able to use SQL cmdlets like Invoke-SQLcmd. In fact, SQL Module is coming with sql
server installation and the only thing you should do is running Import-Module -Name sqlps command.
However, if you are using a lower version of SQL Server, since there is not a sql module you should be
importing sql assemblies at the beginning of our powershell script.
Comments
Anonymous
November 07, 2013
The formatting of this article causes the words to run off the edge. (in IE and Chrome at least)Anonymous
November 08, 2013
Not good example to set sql job scripts to run from desktop locationAnonymous
November 09, 2013
super and it worked. However, I had to create the PerfmonCounterData table based on the stored procedure. The table script provided is not related to this blog.Anonymous
January 21, 2014
Hi all, sorry for the late response first. I am back to my blog again.Anonymous
January 21, 2014
The comment has been removedAnonymous
January 21, 2014
@Reader, yes you are right, i didn't care just it is a test scenario, but edited it since my readers are disturbed with it.Anonymous
January 21, 2014
@PerfmonCounterData table script not given , thanks for it. Edited it and developped the powershell script as well. Please try the new one :)Anonymous
April 30, 2014
Great article. I am setting up data collection on a centralized server. I tried using the script with a text file of server information. I am not able to connect to remote computers. Can you please guide me what needs to be done in order to run this script on remote servers? Do I need to have a port that needs to be opened or some service? FYi..the WinRm and WMI services are already running on target machinesAnonymous
May 14, 2014
Thanks Dave. Pls check the permissions of the acoount first, it requires local admin permissions for the server and if you write the exact error message ı can help you more on this.