Construct a special multi statement table function for checking SQL Server s health

Construct a special multi statement table function for checking SQL Server s health

Construct a special multi-statement table function for checking SQL Server's health

SQLShack

SQL Server training Español

Construct a special multi-statement table function for checking SQL Server’ s health

December 24, 2015 by Eli Leiba

The Problem

Checking the many SQL Servers health conditions is one of the DBA basic tasks. Monitoring many servers and databases, day after day can be a very tedious job. There are many aspects to look for when checking the server performance figures. Such aspects include among others: CPU, Read and Write Disk counters, Various memory counters and locks performance counters. The DBA needs a tool that checks the most important counters and output a report that states whether the server is considered to be healthy or not. For every aspect, a counter is chosen to represent it to be included in the overall report. I have chosen here Buffer cache hit ratio counter for memory category, % user time for CPU category, Avg. Disk Sec/Read and Avg. Disk Sec/Write for the Disk category and Avg. Wait Time (ms) for the Locks category. There are many other, good and helpful categories that can be used but I have selected these after referencing many documentation sources.

The suggested solution

The suggested solution for checking the server’s health conditions is to construct a Multi Statement table valued function that will show, in one glance, a comprehensive “Look over” on the most important counters values on the server and show the Resulting result set to the DBA. Each counter is analyzed inside the function according to books, online documentation, best knowledge, and given a good or bad status. If all aspects are ‘Good’ the server status is ‘Healthy’, else then a ‘Sick’ status is given.

Here is my suggestion for list of the most important counters

The counters table consists of category, counter name, description, and good values Range, bad value ranges Category Counter Name Description Good range values Bad range values Memory/Buffer Manager Buffer cache hit ratio The buffer cache hit ratio counter represents an indication of the percentage of data pages that exists in SQL Server’s memory and without forcing the Server to get them from the disk. The closer this number is to 100 percent, the better. The common threshold considered for this counter is around 90%. A lower hit ratio value than 90% indicates clearly a memory problem and is a clear indication that memory should be extended/added to the SQL Server RAM. >= 90% < 90% CPU/ Processor % user time The % user time counter in the CPU / Processor category stands for the percentage of the processor non-idle time spent on executing the SQL user processes The recommendation value for THE Processor: % user time is below 70% There are some SQL experts state that 80% should be the threshold for CPU problems instead if 70 %. This counter is also called CPU Usage % in some SQL versions =< 70% > 70% Disk Avg. Disk Sec/Read The Avg. Disk Sec/ Read counter stands for the measure of disk latency representing the average time, in milliseconds. For each read to disk where > 20 is considered being poor, <20 is considered being good/fair, <12 is considered to be better and <8 is considered the best =< 20MS > 20MS Disk Avg. Disk Sec/Write The Avg. Disk Sec/Write counter stands for a measure of disk latency representing the average time, in milliseconds, for each write to disk, where non-cached writes > 20 is considered being poor, <20 is considered being fair, <12 is considered better, <8 is considered the best level This counter differs significantly from the cached writes counter where > 4 is considered poor, <4 is considered fair, <2 better, <1 is the considered the best. For OLTP databases, the lower this number the better, especially for disks holding the Transaction log. =< 20MS > 20MS Locks Avg Wait Time (in ms) The average wait time, in milliseconds, for each lock request that had to wait. An average wait time longer than 500ms may indicate excessive blocking. This value should generally correlate to the ‘Lock Waits/sec’ counter =< 500MS > 500MS Here is the user defined multi-statement table valued function T-SQL code: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 Create FUNCTION getSQLServerHealthState ()RETURNS@SQLServerHealthState table ( counter_name Varchar(100), counter_value decimal (7,2), verdict varchar(10) )ASBEGIN /* Memory cache hit ratio counter */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value),iif (avg(cntr_value) >= 90 ,'good', 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Buffer cache hit ratio' group by counter_name /* CPU usage counter */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value), iif (avg(cntr_value) <= 70 , 'good', 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'CPU Usage %' group by counter_name /* Locks counter */ INSERT INTO @SQLServerHealthState select counter_name,avg(cntr_value) , iif (avg(cntr_value) <= 500 , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Lock Wait Time (ms)' group by counter_name /* Disk Read */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value),iif (avg(cntr_value) <= 20 , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Disk Read IO/sec' group by counter_name /* Disk write */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value),iif (avg(cntr_value) <= 20 , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Disk Write IO/sec' group by counter_name insert into @SQLServerHealthState select 'SERVER STATE', NULL , (SELECT IIF (COUNT(*) = 5 ,'Healty' , 'Sick') from @SQLServerHealthState where verdict = 'good') RETURNENDGO Note: create and compile the function in the master database

Explanation for the code

I called my multi statement, table valued function getSQLServerHealthState, it gets no parameters and outputs, as the result set a table with the selected five counters, their values and the verdict: good or bad value. The functions query the sys.dm_os_performance_counters dynamic view. It assumes that there exists more than one counter with the same name corresponding to various SQL instances. Because there can be several values for each counter, a AVG group function is used in order to get the mean value for each counter for all of the servers activity on each counter. An IIF function gets the verdict by operating directly on the result value of the AVG function. For each counter, the rule from documentation is applied. At the end, a summary line is added. If all rows are set to ‘good’ then healthy status is given, else a Sick status is given The function was successfully tested on my server which is SQL Server 2014 express edition. Here is an example for the function’s execution done on my server: 12345 Use masterGoSELECT * from dbo.getSQLServerHealthState()

A code improvement suggestion for the function

A suggested improvement for the code will be to put all the threshold values in a Dedicated table and access it with a scalar function. Then use this function inside the Multi-statement table function. Thus, changing the threshold values will not force code changes inside the function Definition.

Code improvement steps

Create the threshold table in master database: CREATE TABLE dbo.thresholds ( counter_key VARCHAR(32) ,threshold_value INT ) GO INSERT INTO dbo.thresholds ( counter_key ,threshold_value ) VALUES ( ‘Buffer cache hit ratio’ ,90 ) ,( ‘CPU Usage %’ ,70 ) ,( ‘Lock Wait Time (ms)’ ,500 ) ,( ‘Disk Read IO/sec’ ,20 ) ,( ‘Disk Write IO/sec’ ,20 ) GO The next step is to Create a scalar function called GetThresholdValue in order to access the threshold values from the table, since it is an inner use scalar function, no errors are assumed, so not error handling is coded in the function’s definition. 123456789101112131415161718 CREATE FUNCTION GetThresholdValue (@key VARCHAR(32))RETURNS INTASBEGIN -- Declare the return variable DECLARE @Result INT -- T-SQL statements to compute the return value here SELECT @Result = threshold_value FROM dbo.thresholds WHERE counter_key = @key -- Return the result of the function RETURN @ResultENDGO Finally, modify the getSQLServerHealthState function so that it will use the inner scalar function instead of “hard coding” the threshold values. Here is the modified and improved T-SQL code for the function: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 alter FUNCTION [dbo].[getSQLServerHealthState] ()RETURNS@SQLServerHealthState table (counter_name Varchar(100), counter_value decimal (7,2), verdict varchar(10))ASBEGIN /* Memory cache hit ratio counter */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value) , iif (avg(cntr_value) >= dbo.GetThresholdValue ( 'Buffer cache hit ratio'), 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Buffer cache hit ratio' group by counter_name /* CPU usage counter */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value) , iif (avg(cntr_value) <= dbo.GetThresholdValue ( 'CPU Usage %') , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'CPU Usage %' group by counter_name /* Locks counter */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value) , iif (avg(cntr_value) <= dbo.GetThresholdValue ( 'Lock Wait Time (ms)') , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Lock Wait Time (ms)' group by counter_name /* Disk Read */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value) , iif (avg(cntr_value) <= dbo.GetThresholdValue ( 'Disk Read IO/sec' ) , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Disk Read IO/sec' group by counter_name /* Disk write */ INSERT INTO @SQLServerHealthState select counter_name , avg(cntr_value) , iif (avg(cntr_value) <= dbo.GetThresholdValue ( 'Disk Write IO/sec') , 'good' , 'bad') as verdict from sys.dm_os_performance_counters where counter_name = 'Disk Write IO/sec' group by counter_name insert into @SQLServerHealthState select 'SERVER STATE', NULL , (SELECT IIF (COUNT(*) = 5 ,'Healty' , 'Sick') from @SQLServerHealthState where verdict = 'good') RETURNENDGO
Author Recent Posts Eli LeibaEli Leiba is a senior application DBA at Israel Electric Company, a teacher at Microsoft CTEC, and senior database consultant with 24 years of experience working with both SQL Server and Oracle RDBMS. He is certified in Oracle and SQL Server database administration and implementation and has a B.S. in Computer Science.He can be reached at: [email protected]

View all posts by Eli Leiba Latest posts by Eli Leiba (see all) Creating a stored procedure to fix orphaned database users - January 25, 2016 Creating a gap in sequences – TSQL Stored Procedure advisor - January 6, 2016 Construct a special multi-statement table function for checking SQL Server’ s health - December 24, 2015

Related posts

SQL Server memory performance metrics – Part 4 – Buffer Cache Hit Ratio and Page Life Expectancy Troubleshooting SQL Server issues with sys.dm_os_performance_counters SQL Server multi-statement table-valued functions SQL Server memory performance metrics – Part 2 – available bytes, total server, and target server memory SQL Server memory performance metrics – Part 5 – understanding Lazy Writes, Free List Stalls/sec, and Memory Grants Pending 981 Views

Follow us

Popular

SQL Convert Date functions and formats SQL Variables: Basics and usage SQL PARTITION BY Clause overview Different ways to SQL delete duplicate rows from a SQL Table How to UPDATE from a SELECT statement in SQL Server SQL Server functions for converting a String to a Date SELECT INTO TEMP TABLE statement in SQL Server SQL WHILE loop with simple examples How to backup and restore MySQL databases using the mysqldump command CASE statement in SQL Overview of SQL RANK functions Understanding the SQL MERGE statement INSERT INTO SELECT statement overview and examples SQL multiple joins for beginners with examples Understanding the SQL Decimal data type DELETE CASCADE and UPDATE CASCADE in SQL Server foreign key SQL Not Equal Operator introduction and examples SQL CROSS JOIN with examples The Table Variable in SQL Server SQL Server table hints – WITH (NOLOCK) best practices

Trending

SQL Server Transaction Log Backup, Truncate and Shrink Operations Six different methods to copy tables between databases in SQL Server How to implement error handling in SQL Server Working with the SQL Server command line (sqlcmd) Methods to avoid the SQL divide by zero error Query optimization techniques in SQL Server: tips and tricks How to create and configure a linked server in SQL Server Management Studio SQL replace: How to replace ASCII special characters in SQL Server How to identify slow running queries in SQL Server SQL varchar data type deep dive How to implement array-like functionality in SQL Server All about locking in SQL Server SQL Server stored procedures for beginners Database table partitioning in SQL Server How to drop temp tables in SQL Server How to determine free space and file size for SQL Server databases Using PowerShell to split a string into an array KILL SPID command in SQL Server How to install SQL Server Express edition SQL Union overview, usage and examples

Solutions

Read a SQL Server transaction logSQL Server database auditing techniquesHow to recover SQL Server data from accidental UPDATE and DELETE operationsHow to quickly search for SQL database data and objectsSynchronize SQL Server databases in different remote sourcesRecover SQL data from a dropped table without backupsHow to restore specific table(s) from a SQL Server database backupRecover deleted SQL data from transaction logsHow to recover SQL Server data from accidental updates without backupsAutomatically compare and synchronize SQL Server dataOpen LDF file and view LDF file contentQuickly convert SQL code to language-specific client codeHow to recover a single table from a SQL Server database backupRecover data lost due to a TRUNCATE operation without backupsHow to recover SQL Server data from accidental DELETE, TRUNCATE and DROP operationsReverting your SQL Server database back to a specific point in timeHow to create SSIS package documentationMigrate a SQL Server database to a newer version of SQL ServerHow to restore a SQL Server database backup to an older version of SQL Server

Categories and tips

►Auditing and compliance (50) Auditing (40) Data classification (1) Data masking (9) Azure (295) Azure Data Studio (46) Backup and restore (108) ►Business Intelligence (482) Analysis Services (SSAS) (47) Biml (10) Data Mining (14) Data Quality Services (4) Data Tools (SSDT) (13) Data Warehouse (16) Excel (20) General (39) Integration Services (SSIS) (125) Master Data Services (6) OLAP cube (15) PowerBI (95) Reporting Services (SSRS) (67) Data science (21) ►Database design (233) Clustering (16) Common Table Expressions (CTE) (11) Concurrency (1) Constraints (8) Data types (11) FILESTREAM (22) General database design (104) Partitioning (13) Relationships and dependencies (12) Temporal tables (12) Views (16) ▼Database development (418) Comparison (4) Continuous delivery (CD) (5) Continuous integration (CI) (11) Development (146) Functions (106) Hyper-V (1) Search (10) Source Control (15) SQL unit testing (23) Stored procedures (34) String Concatenation (2) Synonyms (1) Team Explorer (2) Testing (35) Visual Studio (14) DBAtools (35) DevOps (23) DevSecOps (2) Documentation (22) ETL (76) ►Features (213) Adaptive query processing (11) Bulk insert (16) Database mail (10) DBCC (7) Experimentation Assistant (DEA) (3) High Availability (36) Query store (10) Replication (40) Transaction log (59) Transparent Data Encryption (TDE) (21) Importing, exporting (51) Installation, setup and configuration (121) Jobs (42) ►Languages and coding (686) Cursors (9) DDL (9) DML (6) JSON (17) PowerShell (77) Python (37) R (16) SQL commands (196) SQLCMD (7) String functions (21) T-SQL (275) XML (15) Lists (12) Machine learning (37) Maintenance (99) Migration (50) Miscellaneous (1) ▼Performance tuning (869) Alerting (8) Always On Availability Groups (82) Buffer Pool Extension (BPE) (9) Columnstore index (9) Deadlocks (16) Execution plans (125) In-Memory OLTP (22) Indexes (79) Latches (5) Locking (10) Monitoring (100) Performance (196) Performance counters (28) Performance Testing (9) Query analysis (121) Reports (20) SSAS monitoring (3) SSIS monitoring (10) SSRS monitoring (4) Wait types (11) ►Professional development (68) Professional development (27) Project management (9) SQL interview questions (32) Recovery (33) Security (84) Server management (24) SQL Azure (271) SQL Server Management Studio (SSMS) (90) SQL Server on Linux (21) ►SQL Server versions (177) SQL Server 2012 (6) SQL Server 2016 (63) SQL Server 2017 (49) SQL Server 2019 (57) SQL Server 2022 (2) ►Technologies (334) AWS (45) AWS RDS (56) Azure Cosmos DB (28) Containers (12) Docker (9) Graph database (13) Kerberos (2) Kubernetes (1) Linux (44) LocalDB (2) MySQL (49) Oracle (10) PolyBase (10) PostgreSQL (36) SharePoint (4) Ubuntu (13) Uncategorized (4) Utilities (21) Helpers and best practices BI performance counters SQL code smells rules SQL Server wait types © 2022 Quest Software Inc. ALL RIGHTS RESERVED. GDPR Terms of Use Privacy
Share:
0 comments

Comments (0)

Leave a Comment

Minimum 10 characters required

* All fields are required. Comments are moderated before appearing.

No comments yet. Be the first to comment!