Introduction
Have you ever been asked for information you couldn't provide because you didn't have an historical monitoring tool? Try this light weight technique which records high level performance statistics for both SQL Server and SQL Server databases.
Technique
- Select a SQL Server instance and database to host the data. I used one of our development servers and called my database SrvStat.
- Create two tables; one for server statistics and one for database statistics: See the CreateTables.sql in the resources section at the bottom.
3. Create a DTS package to transfer data from the servers you want to monitor into these tables using the following queries. I created one DTS for server monitoring and one for database monitoring:
- For server monitoring (You can add as many source servers as you choose. The process is the same for each.)
Each transform task contains the counters that you need in a query.
- Query Excerpt: (These counters are cumulative and are reset to zero when SQL Server is restarted).
select @@servername AS ServName, getdate() AS SampDate, @@connections AS ConnQty, @@cpu_busy AS CPUBusyMSQty, @@io_busy AS IOBusyMSQty, @@idle AS IdleMSQty, @@pack_received AS PackRecvQty, @@pack_sent AS PackSentQty, @@packet_errors AS PackErrQty, @@total_read AS TotReadQty, @@total_write AS TotWriteQty, @@total_errors AS TotIOErrQty
- For database monitoring (You can add as many source servers as you choose. The process is the same for each.)
As you can see we are making simple transforms of each set of data.
- Script Excerpt: (::fn_virtualfilestats is cumulative and are reset to zero when SQL Server is restarted)
The code for this section is in the Resources section as MonitoringServers.sql
4. Schedule each package to run on a fixed schedule each day.
5. Since the counters listed above are cumulative, create the following two views (one for each base table) to break the data down to the interval you have chosen (daily in our case). Basically, these views subtract the previous row's counters from the current row to get a time interval total. (This code is in the Resources section as MonitoringServers2.sql).
-- Database stats create view vDayDBStat as select top 100 percent d2.SrvName, d2.DBName, d2.LogFileName, d2.SampDate, case when d1.ReadQty > d2.ReadQty then d2.ReadQty when d1.ReadQty <= d2.ReadQty then d2.ReadQty - d1.ReadQty end as ReadQty, case when d1.WriteQty > d2.WriteQty then d2.WriteQty when d1.WriteQty <= d2.WriteQty then d2.WriteQty - d1.WriteQty end as WriteQty, case when d1.ByteReadQty > d2.ByteReadQty then d2.ByteReadQty when d1.ByteReadQty <= d2.ByteReadQty then d2.ByteReadQty - d1.ByteReadQty end as ByteReadQty, case when d1.ByteWriteQty > d2.ByteWriteQty then d2.ByteWriteQty when d1.ByteWriteQty <= d2.ByteWriteQty then d2.ByteWriteQty - d1.ByteWriteQty end as ByteWriteQty, case when d1.IOStallMSQty > d2.IOStallMSQty then d2.IOStallMSQty when d1.IOStallMSQty <= d2.IOStallMSQty then d2.IOStallMSQty - d1.IOStallMSQty end as IOStallMSQty from DayDBStat d1, DayDBStat d2 where d1.SrvName = d2.SrvName and d1.DBName = d2.DBName and d1.LogFileName = d2.LogFileName and d1.SampDate < d2.SampDate and DATEDIFF (day, d1.SampDate, d2.SampDate) = 1 order by d1.SrvName, d1.DBName, d1.LogFileName, d1.SampDate GO -- Server stats create view vDaySrvStat as select top 100 percent d2.SrvName, d2.SampDate, case when d1.ConnQty > d2.ConnQty then d2.ConnQty when d1.ConnQty <= d2.ConnQty then d2.ConnQty - d1.ConnQty end as ConnQty, case when d1.CPUBusyMSQty > d2.CPUBusyMSQty then d2.CPUBusyMSQty when d1.CPUBusyMSQty <= d2.CPUBusyMSQty then d2.CPUBusyMSQty - d1.CPUBusyMSQty end as CPUBusyMSQty, case when d1.IOBusyMSQty > d2.IOBusyMSQty then d2.IOBusyMSQty when d1.IOBusyMSQty <= d2.IOBusyMSQty then d2.IOBusyMSQty - d1.IOBusyMSQty end as IOBusyMSQty, case when d1.IdleMSQty > d2.IdleMSQty then d2.IdleMSQty when d1.IdleMSQty <= d2.IdleMSQty then d2.IdleMSQty - d1.IdleMSQty end as IdleMSQty, case when d1.PackRecvQty > d2.PackRecvQty then d2.PackRecvQty when d1.PackRecvQty <= d2.PackRecvQty then d2.PackRecvQty - d1.PackRecvQty end as PackRecvQty, case when d1.PackSentQty > d2.PackSentQty then d2.PackSentQty when d1.PackSentQty <= d2.PackSentQty then d2.PackSentQty - d1.PackSentQty end as PackSentQty, case when d1.PackErrQty > d2.PackErrQty then d2.PackErrQty when d1.PackErrQty <= d2.PackErrQty then d2.PackErrQty - d1.PackErrQty end as PackErrQty, case when d1.TotReadQty > d2.TotReadQty then d2.TotReadQty when d1.TotReadQty <= d2.TotReadQty then d2.TotReadQty - d1.TotReadQty end as TotReadQty, case when d1.TotWriteQty > d2.TotWriteQty then d2.TotWriteQty when d1.TotWriteQty <= d2.TotWriteQty then d2.TotWriteQty - d1.TotWriteQty end as TotWriteQty, case when d1.TotIOErrQty > d2.TotIOErrQty then d2.TotIOErrQty when d1.TotIOErrQty <= d2.TotIOErrQty then d2.TotIOErrQty - d1.TotIOErrQty end as TotIOErrQty from DaySrvStat d1, DaySrvStat d2 where d1.SrvName = d2.SrvName and d1.SampDate < d2.SampDate and DATEDIFF (day, d1.SampDate, d2.SampDate) = 1 order by d1.SrvName, d1.SampDate GO
Results
Now, when you query these views, you get totals by server/database based on the time interval you choose. I'm reasonably certain these views are correct. If you find a bug, please let me know.
For our presentation layer, we created Excel spread sheets which link to these views and create bar graphs (managers love graphs) for trend analysis. We are currently working on upgrading this process (mostly for the learning experience) to SQL Server 2005, SSIS, SSAS, and SSRS for the presentation layer.
Conclusion
If you have any questions about the @@ counters or ::fn_virtualfilestats, they are well documented in Books Online. Obviously, there are a variety of ways to accomplish each step. We chose to keep daily statistics but you can keep more or less frequent intervals by simply changing the execution schedule on the DTS packages. This facility is relatively simple to set up. I admit, we're a small shop. But we've been running this process since Dec '04 and the database which hosts this data is only 180 MB. It has a small footprint and runs very quickly and reliably. I usually forget about it until management comes to us with capacity planning questions.