Using Zabbix to Monitor MS SQL Server Database

Preface

There is often a need to notify the administrator in real-time about database-related issues.

This article will describe what needs to be configured in Zabbix to monitor the MS SQL Server database.

I would like to emphasize that detailed configuration steps will not be provided; however, formulas and general recommendations, as well as a detailed description of how to add custom data items via stored procedures, will be presented in this article.
Only the main performance counters will be covered here.

Solution

First, I will outline all the performance counters (via data items in Zabbix) that we need:

  1. Logical Disk
    1. Avg Disk sec/Read
      Indicates the average time in seconds taken to read data from the disk. The average value of the performance counter Avg. Disk sec/Read should not exceed 10 milliseconds. The maximum value of the performance counter Avg. Disk sec/Read should not exceed 50 milliseconds.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read], and it is also important to monitor the specific disk, for example: perf_counter[LogicalDisk(C:)Avg. Disk sec/Read]

      Trigger Examples:
      {NODE_NAME:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read].last()}>0.005, severity-high
      and
      {NODE_NAME:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read].last()}>0.0025, severity-medium

    2. Avg Disk sec/Write
      Indicates the average time in seconds taken to write data to the disk. The average value of the performance counter Avg. Disk sec/Write should not exceed 10 milliseconds. The maximum value of the performance counter Avg. Disk sec/Write should not exceed 50 milliseconds.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write], and it is also important to monitor the specific disk, for example: perf_counter[LogicalDisk(C:)Avg. Disk sec/Write]

      Trigger Examples:
      {NODE_NAME:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write].last()}>0.005, severity-high
      and
      {NODE_NAME:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write].last()}>0.0025, severity-medium

    3. Avg Disk Queue Length

      Average Disk Queue Length. It reflects the number of disk requests waiting to be processed over a specific time interval. A queue of no more than 2 requests for a single disk is considered normal. If there are more than two requests in the queue, the disk may be overloaded and unable to process incoming requests. To clarify which operations the disk cannot handle, you can use the counters Avg. Disk Read Queue Length (read request queue) and Avg. Disk Write Queue Length (write request queue).
      The Avg. Disk Queue Length is not measured but rather calculated using Little's law from queueing theory. According to this law, the number of requests waiting to be processed is, on average, equal to the request arrival rate multiplied by the request processing time. That is, in our case, Avg. Disk Queue Length = (Disk Transfers/sec) * (Avg. Disk sec/Transfer).

      Avg. Disk Queue Length is presented as one of the key counters for determining disk subsystem load; however, for an adequate assessment, it is essential to have a clear understanding of the physical structure of the storage system. For instance, for a single hard disk, a critical value is considered to be more than 2, while if the disk is part of a RAID array of 4 disks, concern arises at a value exceeding 4*2=8.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk Queue Length], and it's also important to monitor the specific disk, for example: perf_counter[LogicalDisk(C:)Avg. Disk Queue Length]

  2. Memory
    1. Pages/sec
      Displays the number of pages that SQL Server has read from or written to disk to resolve requests for memory pages that were not loaded into RAM at the time of access. This value is the sum of the Pages Input/sec and Pages Output/sec metrics, and it also takes into account page swapping (paging) of system cache memory for accessing application data files. Additionally, it includes swapping of uncached files that are directly mapped into memory. This is the primary counter to watch if there is a significant load on memory usage and related excessive paging. This counter characterizes the amount of swapping, and its normal (not peak) value should be close to zero. An increase in swapping indicates a need to add RAM or reduce the number of applications running on the server.

      Zabbix: perf_counter[MemoryPages/sec]
      Trigger Example:
      {NODE_NAME:perf_counter[MemoryPages/sec].min(5m)}>1000, level-info

    2. Page Faults/sec

      This value represents the page fault counter. A page fault occurs when a process references a page in virtual memory that is not in the working set of RAM. This counter accounts for both page faults that require a disk access and those caused by a page being out of the working set in RAM. Most processors can handle second type page faults without significant delays. However, handling first type page faults requiring disk access can lead to considerable delays.

      Zabbix: perf_counter[MemoryPage Faults/sec]
      Trigger Example:
      {NODE_NAME:perf_counter[MemoryPage Faults/sec].min(5m)}>1000, level-info

    3. Available Bytes

      Tracks the amount of available memory in bytes for executing various processes. Low readings indicate insufficient memory. The solution is to increase memory. This counter should typically remain above 5000 KB.
      It makes sense to set a threshold for Available Mbytes manually based on the following:

      • 50% free memory available = Excellent
      • 25% memory available = Requires attention
      • 10% free = Possible issues
      • Less than 5% memory available = Critical for speed, intervention needed.
      Zabbix: perf_counter[MemoryAvailable Bytes]

  3. Processor (Total): % Processor Time
    This counter shows the percentage of time the processor was occupied performing operations for non-idle threads. This value can be seen as the share of time dedicated to useful work. Each processor can be assigned to an idle thread that consumes unproductive CPU cycles not utilized by other threads. This counter typically shows brief spikes, which may reach 100 percent. However, if prolonged periods are observed where CPU utilization exceeds 80 percent, the system will be more efficient with a greater number of processors.

    Zabbix: perf_counter[Processor(_Total)% Processor Time], it may also be shown by cores
    Trigger Example:
    {NODE_NAME:perf_counter[Processor(_Total)% Processor Time].min(5m)}>80, level-info

  4. Network Interface (*): % Bytes Total/sec
    The total number of bytes transmitted and received per second across all interfaces. This is the throughput of the interface (in bytes). It is necessary to compare this counter's value to the maximum throughput of the network card. Generally, this counter should show no more than 50% utilization of the network adapter's bandwidth.
    Zabbix: perf_counter[Network Interface(*)Bytes Sent/sec]
  5. MS SQL Server: Access Methods
    The Access Methods object in SQL Server provides counters that help monitor access to logical data within the database. Physical access to database pages on disk is controlled through buffer manager counters. Monitoring data access methods in the database helps determine whether query performance can be improved by adding or modifying indexes, adding or moving sections, adding files or file groups, defragmenting indexes, or modifying query text. Moreover, with the Access Methods object counters, one can track the size of data, indexes, and free space in the database, monitoring volume and fragmentation for each server instance. Excessive index fragmentation can significantly reduce performance.
    1. Page Splits/sec
      The number of page splits per second caused by index page overflow. A high value for this indicator means that during insert and update operations, SQL Server has to perform a large number of resource-intensive page-splitting operations and move part of the existing page to a new location. Such operations should be avoided if possible. The issue can be addressed in two ways:
      — create a clustered index for auto-incrementing columns. In this case, new records will not be placed within pages already occupied by data but will sequentially occupy new pages;
      — rebuild the indexes by increasing the Fillfactor parameter. This parameter allows reserving free space in index pages that will be used to accommodate new data without the need for page-splitting operations.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Access MethodsPage Splits/sec",30]
      Trigger Example: {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Access MethodsPage Splits/sec",30].last()}>{NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:SQL StatisticsBatch Requests/sec",30].last()}/5, level-info
    2. Full Scans/sec
      The number of unlimited full scan operations per second. These operations include scanning the base table and full index scans. A steady increase in this indicator may indicate system degradation (lack of necessary indexes, high fragmentation, non-usage of existing indexes by the optimizer, presence of unused indexes). However, it is worth noting that a full scan in small tables is not necessarily bad, as if the entire table can fit in RAM, a full scan will actually be faster. But in most cases, a steady increase in this counter indicates system degradation. This is only applicable for OLTP systems. In OLAP systems, continuous full scans are normal.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Access MethodsFull Scans/sec",30]

  6. MS SQL Server: Buffer Manager
    The Buffer Manager object provides counters to observe how SQL Server uses the following resources:
    — memory for storing data pages;
    — counters that monitor physical I/O when SQL Server reads and writes database pages;
    — buffer pool extension to increase the buffer cache using fast non-volatile memory, such as solid-state drives (SSD);
    — monitoring memory and counters used by SQL Server provides the following insights;
    — whether there are any "bottlenecks" caused by insufficient physical memory. If frequently accessed data cannot be cached, SQL Server is forced to read it from the disk;
    — whether query execution efficiency can be improved by increasing memory or allocating additional memory for data caching or storing internal SQL Server structures;
    — how often SQL Server reads data from the disk. Compared to other operations such as accessing memory, physical I/O takes longer. Reducing I/O volume can improve query execution performance.
    1. Buffer Cache hit ratio
      Indicates how effectively SQL Server can place data in the buffer cache. The higher this value, the better, as for efficient access by SQL Server to data pages, they must reside in the buffer cache, and physical I/O operations should be minimized. If a consistent decline in the average value of this counter is observed, consideration should be given to adding RAM. This metric should always be above 90% for OLTP systems and above 50% for OLAP systems.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Buffer ManagerBuffer cache hit ratio",30]
      Trigger Examples: {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Buffer ManagerBuffer cache hit ratio",30].last()}<70, level-high
      and
      {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Buffer ManagerBuffer cache hit ratio",30].last()}<80, level-medium
    2. Page life expectancy
      Indicates how long a page will remain in memory in its current state. If the value continuously drops, it means the system is abusing the buffer pool. Consequently, potential memory usage may lead to issues that reduce performance. It's important to note that there is no universal metric below which one can definitively judge that the system is abusing the buffer pool (the 300 seconds threshold became outdated with MS SQL Server 2012).
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Buffer ManagerPage life expectancy",30]
      Trigger Example: {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Buffer ManagerPage life expectancy",30].last()}<5, level-info

  7. MS SQL Server: General Statistics
    The General Statistics object in SQL Server provides counters for monitoring the overall server activity, such as the number of concurrent connections and the number of users per second connecting to or disconnecting from the computer where the SQL Server instance is running. These metrics are useful in large online transaction processing (OLTP) systems, where a high number of clients continuously connect and disconnect from the SQL Server instance.
    1. Process blocked
      The number of currently blocked processes.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:General StatisticsProcesses blocked",30]
      Trigger Example: ({NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:General StatisticsProcesses blocked",30].min(2m,0)}>=0)
      and ({NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:General StatisticsProcesses blocked",30].time(0)}>=50000)
      and ({NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:General StatisticsProcesses blocked",30].time(0)}<=230000), level-info (this signal restriction is from 05:00 to 23:00)
    2. User Connections
      The number of users currently connected to the SQL Server.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:General StatisticsUser Connections",30]

  8. MS SQL Server: Locks
    The Locks object in Microsoft SQL Server provides information about the SQL Server locks acquired for specific types of resources. Locks are issued on SQL Server resources such as rows read or modified by a transaction to prevent multiple transactions from simultaneously accessing those resources. For example, if an exclusive (X) lock is obtained by a transaction on a row in a table, no other transaction can modify that row until the lock is released. Minimizing lock usage increases concurrency, which can enhance overall performance. Multiple instances of the Locks object can be tracked simultaneously, each representing a lock on a specific type of resource.
    1. Average Wait Time (ms)
      The average wait time (in milliseconds) for all lock requests that required waiting. This counter indicates how much time, on average, user processes spend in queue to obtain a lock on a resource. The maximum acceptable value for this counter is entirely dependent on your workload; determining a median value for all applications can be difficult here. A too high value for this counter may indicate locking issues in your database.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Average Wait Time (ms)",30]
      Trigger Example: {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Average Wait Time (ms)",30].last()}>=500, level-info
    2. Lock Wait Time (ms)
      The total lock wait time (in milliseconds) over the last second.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Lock Wait Time (ms)",30]
    3. Lock Waits/sec
      The number of times in the last second that a thread had to wait due to a lock request.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Lock Waits/sec",30]
    4. Lock Timeouts/sec
      The number of times a lock cannot be acquired via spinning before the timeout expires and the thread goes inactive. The SQL Server spin counter configuration parameter defines the number of "spins" a thread will attempt before timing out.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Lock Timeouts/sec",30]
      Trigger Example: {NODE_NAME:perf_counter["MSSQL$INSTANCE_NAME:Locks(_Total)Locks(_Total)Lock Timeouts/sec",30].last()}>1000, level-info
    5. Lock Requests/sec
      The number of requests per second of the specified type of lock.
      Zabbix: perf_counter[«MSSQL$INSTANCE_NAME:Locks(_Total)Lock Requests/sec»,30]
      Trigger Example: {NODE_NAME:perf_counter[«MSSQL$INSTANCE_NAME:Locks(_Total)Lock Requests/sec»,30].last()} > 500000, level-info
    6. Lock Number of Deadlocks/sec
      The number of lock requests per second leading to deadlocks. The presence of deadlocks indicates poorly constructed queries that block shared resources.
      Zabbix: perf_counter[«MSSQL$INSTANCE_NAME:Number of Deadlocks/sec»,30]
      Trigger Example: {NODE_NAME:perf_counter[«MSSQL$INSTANCE_NAME:Locks(_Total)Number of Deadlocks/sec»,30].last()} > 1, level-high

  9. MS SQL Server: Memory Manager
    The Memory Manager object in Microsoft SQL Server provides counters for monitoring memory usage across the entire server. Overseeing the memory usage of the server helps evaluate user actions and resource consumption, aiding in identifying performance bottlenecks. Managing memory utilized by the SQL Server instance can help determine:
    — whether there are shortages in insufficient physical memory for caching frequently used data. If memory is lacking, SQL Server must fetch data from disk;
    — whether query performance could improve with additional memory or increased available memory for caching data or SQL Server's internal structures.
    1. Memory Grants Outstanding
      Indicates the total number of processes that have successfully acquired workspace memory. A steady decline in this metric indicates that RAM needs to be increased.
      Zabbix: perf_counter[«MSSQL$INSTANCE_NAME:Memory ManagerMemory Grants Outstanding»,30]
    2. Memory Grants Pending
      Indicates the total number of processes waiting for workspace memory allocation. A steady increase in this metric indicates that RAM needs to be increased.
      Zabbix: perf_counter[«MSSQL$INSTANCE_NAME:Memory ManagerMemory Grants Pending»,30]

  10. MS SQL Server: Statistics
    The Statistics object in Microsoft SQL Server operates counters to monitor compilations and types of queries sent to the SQL Server instance. Tracking the number of compilations and recompilations of queries and the number of batches received by the SQL Server instance provides insight into how quickly SQL Server executes user queries and how effectively the query optimizer processes them.
    1. Batch Requests/sec
      The number of Transact-SQL command packets received per second. This statistic is influenced by any constraints (I/O, number of users, cache size, complexity of queries, etc.). A high number of packet requests indicates a high throughput.
      Zabbix: perf_counter["MSSQL$INSTANCE_NAME:SQL StatisticsBatch Requests/sec",30]

In addition to all the above, you can also configure other data elements (as well as create triggers for them with subsequent notifications). For example:
1) the amount of free disk space
2) sizes of database data and log files
etc.
However, all these metrics do not reflect the real-time query issues.
For this, it is necessary to create your own special counters.
Due to privacy considerations, I will not provide examples of such counters. Moreover, they are uniquely configured for each system. However, I note that for systems like 1C, NAV, and CRM, specialized counters can be created in collaboration with the respective developers.
I will give an example of creating a generalized metric that shows how many requests are executed and how many requests are waiting for execution (paused or blocked) at any given time.
To do this, a stored procedure must be created:
Code

USE [DATABASE_NAME]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [nav].[ZabbixGetCountRequestStatus]
	@Status nvarchar(255)
AS
BEGIN
	/*
		returns the count of requests with the specified status
	*/
	SET NOCOUNT ON;

	select count(*) as [Count]
	from sys.dm_exec_requests ER with(readuncommitted)
	where [status]=@Status
END

Next, you need to go to the folder where Zabbix is located (zabbixconfuserparams.d) and create 2 files with the .ps1 (PowerShell) extension and write the following codes in each of them:
Code for running requests

$SQLServer = "INSTANCE_NAME";
$uid = "LOGIN"; 
$pwd = "PASSWORD";
$Status="running";

$connectionString = "Server = $SQLServer; Database=DATABASE_NAME; Integrated Security = False; User ID = $uid; Password = $pwd;";

$connection = New-Object System.Data.SqlClient.SqlConnection;
$connection.ConnectionString = $connectionString;

#Create a request directly to MSSQL
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure;  
$SqlCmd.CommandText = "nav.ZabbixGetCountRequestStatus";
$SqlCmd.Connection = $Connection;

$paramStatus=$SqlCmd.Parameters.Add("@Status" , [System.Data.SqlDbType]::VarChar);
$paramStatus.Value = $Status;

$connection.Open();
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$SqlAdapter.SelectCommand = $SqlCmd;
$DataSet = New-Object System.Data.DataSet;
$SqlAdapter.Fill($DataSet) > $null;
$connection.Close();

$result = $DataSet.Tables[0].Rows[0]["Count"];

write-host $result;

Code for pending requests

$SQLServer = "INSTANCE_NAME";
$uid = "LOGIN"; 
$pwd = "PASSWORD";
$Status="suspended";

$connectionString = "Server = $SQLServer; Database=DATABASE_NAME; Integrated Security = False; User ID = $uid; Password = $pwd;";

$connection = New-Object System.Data.SqlClient.SqlConnection;
$connection.ConnectionString = $connectionString;

#Create a request directly to MSSQL
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure;  
$SqlCmd.CommandText = "nav.ZabbixGetCountRequestStatus";
$SqlCmd.Connection = $Connection;

$paramStatus=$SqlCmd.Parameters.Add("@Status" , [System.Data.SqlDbType]::VarChar);
$paramStatus.Value = $Status;

$connection.Open();
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$SqlAdapter.SelectCommand = $SqlCmd;
$DataSet = New-Object System.Data.DataSet;
$SqlAdapter.Fill($DataSet) > $null;
$connection.Close();

$result = $DataSet.Tables[0].Rows[0]["Count"];

write-host $result;

Next, you need to create a file with custom parameters and the .conf extension (or add lines to an existing file if it was created earlier) and insert the following lines:
UserParameter=PARAMETER_NAME_EXECUTED_REQUESTS,powershell -NoProfile -ExecutionPolicy Bypass -File FULL_PATHzabbixconfuserparams.dFILENAME_FOR_EXECUTED_REQUESTS.ps1
UserParameter=PARAMETER_NAME_PENDING_REQUESTS,powershell -NoProfile -ExecutionPolicy Bypass -File FULL_PATHzabbixconfuserparams.dFILENAME_FOR_PENDING_REQUESTS.ps1
After that, save the .conf file and restart the Zabbix agent.
Then, add two new items in Zabbix (in this case, names and keys are the same):
PARAMETER_NAME_EXECUTED_REQUESTS
PARAMETER_NAME_PENDING_REQUESTS
You can now create graphs and triggers on the created custom data items.

If the number of pending requests suddenly increases, the next request can output all currently executing and waiting requests with details on where and under which login the request is being made, the text and query plan, as well as other details:
Code

/*Активные, готовые к выполнению и ожидающие запросы, а также те, что явно блокируют другие сеансы*/
with tbl0 as (
	select ES.[session_id]
	      ,ER.[blocking_session_id]
		  ,ER.[request_id]
	      ,ER.[start_time]
	      ,ER.[status]
		  ,ES.[status] as [status_session]
	      ,ER.[command]
		  ,ER.[percent_complete]
		  ,DB_Name(coalesce(ER.[database_id], ES.[database_id])) as [DBName]
	      ,(select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])) as [TSQL]
		  ,(select top(1) [objectid] from sys.dm_exec_sql_text(ER.[sql_handle])) as [objectid]
		  ,(select top(1) [query_plan] from sys.dm_exec_query_plan(ER.[plan_handle])) as [QueryPlan]
	      ,ER.[wait_type]
	      ,ES.[login_time]
		  ,ES.[host_name]
		  ,ES.[program_name]
	      ,ER.[wait_time]
	      ,ER.[last_wait_type]
	      ,ER.[wait_resource]
	      ,ER.[open_transaction_count]
	      ,ER.[open_resultset_count]
	      ,ER.[transaction_id]
	      ,ER.[context_info]
	      ,ER.[estimated_completion_time]
	      ,ER.[cpu_time]
	      ,ER.[total_elapsed_time]
	      ,ER.[scheduler_id]
	      ,ER.[task_address]
	      ,ER.[reads]
	      ,ER.[writes]
	      ,ER.[logical_reads]
	      ,ER.[text_size]
	      ,ER.[language]
	      ,ER.[date_format]
	      ,ER.[date_first]
	      ,ER.[quoted_identifier]
	      ,ER.[arithabort]
	      ,ER.[ansi_null_dflt_on]
	      ,ER.[ansi_defaults]
	      ,ER.[ansi_warnings]
	      ,ER.[ansi_padding]
	      ,ER.[ansi_nulls]
	      ,ER.[concat_null_yields_null]
	      ,ER.[transaction_isolation_level]
	      ,ER.[lock_timeout]
	      ,ER.[deadlock_priority]
	      ,ER.[row_count]
	      ,ER.[prev_error]
	      ,ER.[nest_level]
	      ,ER.[granted_query_memory]
	      ,ER.[executing_managed_code]
	      ,ER.[group_id]
	      ,ER.[query_hash]
	      ,ER.[query_plan_hash]
		  ,EC.[most_recent_session_id]
	      ,EC.[connect_time]
	      ,EC.[net_transport]
	      ,EC.[protocol_type]
	      ,EC.[protocol_version]
	      ,EC.[endpoint_id]
	      ,EC.[encrypt_option]
	      ,EC.[auth_scheme]
	      ,EC.[node_affinity]
	      ,EC.[num_reads]
	      ,EC.[num_writes]
	      ,EC.[last_read]
	      ,EC.[last_write]
	      ,EC.[net_packet_size]
	      ,EC.[client_net_address]
	      ,EC.[client_tcp_port]
	      ,EC.[local_net_address]
	      ,EC.[local_tcp_port]
	      ,EC.[parent_connection_id]
	      ,EC.[most_recent_sql_handle]
		  ,ES.[host_process_id]
		  ,ES.[client_version]
		  ,ES.[client_interface_name]
		  ,ES.[security_id]
		  ,ES.[login_name]
		  ,ES.[nt_domain]
		  ,ES.[nt_user_name]
		  ,ES.[memory_usage]
		  ,ES.[total_scheduled_time]
		  ,ES.[last_request_start_time]
		  ,ES.[last_request_end_time]
		  ,ES.[is_user_process]
		  ,ES.[original_security_id]
		  ,ES.[original_login_name]
		  ,ES.[last_successful_logon]
		  ,ES.[last_unsuccessful_logon]
		  ,ES.[unsuccessful_logons]
		  ,ES.[authenticating_database_id]
		  ,ER.[sql_handle]
	      ,ER.[statement_start_offset]
	      ,ER.[statement_end_offset]
	      ,ER.[plan_handle]
		  ,ER.[dop]
	      ,coalesce(ER.[database_id], ES.[database_id]) as [database_id]
	      ,ER.[user_id]
	      ,ER.[connection_id]
	from sys.dm_exec_requests ER with(readuncommitted)
	right join sys.dm_exec_sessions ES with(readuncommitted)
	on ES.session_id = ER.session_id 
	left join sys.dm_exec_connections EC  with(readuncommitted)
	on EC.session_id = ES.session_id
)
, tbl as (
	select [session_id]
	      ,[blocking_session_id]
		  ,[request_id]
	      ,[start_time]
	      ,[status]
		  ,[status_session]
	      ,[command]
		  ,[percent_complete]
		  ,[DBName]
		  ,OBJECT_name([objectid], [database_id]) as [object]
	      ,[TSQL]
		  ,[QueryPlan]
	      ,[wait_type]
	      ,[login_time]
		  ,[host_name]
		  ,[program_name]
	      ,[wait_time]
	      ,[last_wait_type]
	      ,[wait_resource]
	      ,[open_transaction_count]
	      ,[open_resultset_count]
	      ,[transaction_id]
	      ,[context_info]
	      ,[estimated_completion_time]
	      ,[cpu_time]
	      ,[total_elapsed_time]
	      ,[scheduler_id]
	      ,[task_address]
	      ,[reads]
	      ,[writes]
	      ,[logical_reads]
	      ,[text_size]
	      ,[language]
	      ,[date_format]
	      ,[date_first]
	      ,[quoted_identifier]
	      ,[arithabort]
	      ,[ansi_null_dflt_on]
	      ,[ansi_defaults]
	      ,[ansi_warnings]
	      ,[ansi_padding]
	      ,[ansi_nulls]
	      ,[concat_null_yields_null]
	      ,[transaction_isolation_level]
	      ,[lock_timeout]
	      ,[deadlock_priority]
	      ,[row_count]
	      ,[prev_error]
	      ,[nest_level]
	      ,[granted_query_memory]
	      ,[executing_managed_code]
	      ,[group_id]
	      ,[query_hash]
	      ,[query_plan_hash]
		  ,[most_recent_session_id]
	      ,[connect_time]
	      ,[net_transport]
	      ,[protocol_type]
	      ,[protocol_version]
	      ,[endpoint_id]
	      ,[encrypt_option]
	      ,[auth_scheme]
	      ,[node_affinity]
	      ,[num_reads]
	      ,[num_writes]
	      ,[last_read]
	      ,[last_write]
	      ,[net_packet_size]
	      ,[client_net_address]
	      ,[client_tcp_port]
	      ,[local_net_address]
	      ,[local_tcp_port]
	      ,[parent_connection_id]
	      ,[most_recent_sql_handle]
		  ,[host_process_id]
		  ,[client_version]
		  ,[client_interface_name]
		  ,[security_id]
		  ,[login_name]
		  ,[nt_domain]
		  ,[nt_user_name]
		  ,[memory_usage]
		  ,[total_scheduled_time]
		  ,[last_request_start_time]
		  ,[last_request_end_time]
		  ,[is_user_process]
		  ,[original_security_id]
		  ,[original_login_name]
		  ,[last_successful_logon]
		  ,[last_unsuccessful_logon]
		  ,[unsuccessful_logons]
		  ,[authenticating_database_id]
		  ,[sql_handle]
	      ,[statement_start_offset]
	      ,[statement_end_offset]
	      ,[plan_handle]
		  ,[dop]
	      ,[database_id]
	      ,[user_id]
	      ,[connection_id]
	from tbl0
	where [status] in ('suspended', 'running', 'runnable')
)
, tbl_group as (
	select [blocking_session_id]
	from tbl
	where [blocking_session_id]<>0
	group by [blocking_session_id]
)
, tbl_res_rec as (
	select [session_id]
	      ,[blocking_session_id]
		  ,[request_id]
	      ,[start_time]
	      ,[status]
		  ,[status_session]
	      ,[command]
		  ,[percent_complete]
		  ,[DBName]
		  ,[object]
	      ,[TSQL]
		  ,[QueryPlan]
	      ,[wait_type]
	      ,[login_time]
		  ,[host_name]
		  ,[program_name]
	      ,[wait_time]
	      ,[last_wait_type]
	      ,[wait_resource]
	      ,[open_transaction_count]
	      ,[open_resultset_count]
	      ,[transaction_id]
	      ,[context_info]
	      ,[estimated_completion_time]
	      ,[cpu_time]
	      ,[total_elapsed_time]
	      ,[scheduler_id]
	      ,[task_address]
	      ,[reads]
	      ,[writes]
	      ,[logical_reads]
	      ,[text_size]
	      ,[language]
	      ,[date_format]
	      ,[date_first]
	      ,[quoted_identifier]
	      ,[arithabort]
	      ,[ansi_null_dflt_on]
	      ,[ansi_defaults]
	      ,[ansi_warnings]
	      ,[ansi_padding]
	      ,[ansi_nulls]
	      ,[concat_null_yields_null]
	      ,[transaction_isolation_level]
	      ,[lock_timeout]
	      ,[deadlock_priority]
	      ,[row_count]
	      ,[prev_error]
	      ,[nest_level]
	      ,[granted_query_memory]
	      ,[executing_managed_code]
	      ,[group_id]
	      ,[query_hash]
	      ,[query_plan_hash]
		  ,[most_recent_session_id]
	      ,[connect_time]
	      ,[net_transport]
	      ,[protocol_type]
	      ,[protocol_version]
	      ,[endpoint_id]
	      ,[encrypt_option]
	      ,[auth_scheme]
	      ,[node_affinity]
	      ,[num_reads]
	      ,[num_writes]
	      ,[last_read]
	      ,[last_write]
	      ,[net_packet_size]
	      ,[client_net_address]
	      ,[client_tcp_port]
	      ,[local_net_address]
	      ,[local_tcp_port]
	      ,[parent_connection_id]
	      ,[most_recent_sql_handle]
		  ,[host_process_id]
		  ,[client_version]
		  ,[client_interface_name]
		  ,[security_id]
		  ,[login_name]
		  ,[nt_domain]
		  ,[nt_user_name]
		  ,[memory_usage]
		  ,[total_scheduled_time]
		  ,[last_request_start_time]
		  ,[last_request_end_time]
		  ,[is_user_process]
		  ,[original_security_id]
		  ,[original_login_name]
		  ,[last_successful_logon]
		  ,[last_unsuccessful_logon]
		  ,[unsuccessful_logons]
		  ,[authenticating_database_id]
		  ,[sql_handle]
	      ,[statement_start_offset]
	      ,[statement_end_offset]
	      ,[plan_handle]
		  ,[dop]
	      ,[database_id]
	      ,[user_id]
	      ,[connection_id]
		  , 0 as [is_blocking_other_session]
from tbl
union all
select tbl0.[session_id]
	      ,tbl0.[blocking_session_id]
		  ,tbl0.[request_id]
	      ,tbl0.[start_time]
	      ,tbl0.[status]
		  ,tbl0.[status_session]
	      ,tbl0.[command]
		  ,tbl0.[percent_complete]
		  ,tbl0.[DBName]
		  ,OBJECT_name(tbl0.[objectid], tbl0.[database_id]) as [object]
	      ,tbl0.[TSQL]
		  ,tbl0.[QueryPlan]
	      ,tbl0.[wait_type]
	      ,tbl0.[login_time]
		  ,tbl0.[host_name]
		  ,tbl0.[program_name]
	      ,tbl0.[wait_time]
	      ,tbl0.[last_wait_type]
	      ,tbl0.[wait_resource]
	      ,tbl0.[open_transaction_count]
	      ,tbl0.[open_resultset_count]
	      ,tbl0.[transaction_id]
	      ,tbl0.[context_info]
	      ,tbl0.[estimated_completion_time]
	      ,tbl0.[cpu_time]
	      ,tbl0.[total_elapsed_time]
	      ,tbl0.[scheduler_id]
	      ,tbl0.[task_address]
	      ,tbl0.[reads]
	      ,tbl0.[writes]
	      ,tbl0.[logical_reads]
	      ,tbl0.[text_size]
	      ,tbl0.[language]
	      ,tbl0.[date_format]
	      ,tbl0.[date_first]
	      ,tbl0.[quoted_identifier]
	      ,tbl0.[arithabort]
	      ,tbl0.[ansi_null_dflt_on]
	      ,tbl0.[ansi_defaults]
	      ,tbl0.[ansi_warnings]
	      ,tbl0.[ansi_padding]
	      ,tbl0.[ansi_nulls]
	      ,tbl0.[concat_null_yields_null]
	      ,tbl0.[transaction_isolation_level]
	      ,tbl0.[lock_timeout]
	      ,tbl0.[deadlock_priority]
	      ,tbl0.[row_count]
	      ,tbl0.[prev_error]
	      ,tbl0.[nest_level]
	      ,tbl0.[granted_query_memory]
	      ,tbl0.[executing_managed_code]
	      ,tbl0.[group_id]
	      ,tbl0.[query_hash]
	      ,tbl0.[query_plan_hash]
		  ,tbl0.[most_recent_session_id]
	      ,tbl0.[connect_time]
	      ,tbl0.[net_transport]
	      ,tbl0.[protocol_type]
	      ,tbl0.[protocol_version]
	      ,tbl0.[endpoint_id]
	      ,tbl0.[encrypt_option]
	      ,tbl0.[auth_scheme]
	      ,tbl0.[node_affinity]
	      ,tbl0.[num_reads]
	      ,tbl0.[num_writes]
	      ,tbl0.[last_read]
	      ,tbl0.[last_write]
	      ,tbl0.[net_packet_size]
	      ,tbl0.[client_net_address]
	      ,tbl0.[client_tcp_port]
	      ,tbl0.[local_net_address]
	      ,tbl0.[local_tcp_port]
	      ,tbl0.[parent_connection_id]
	      ,tbl0.[most_recent_sql_handle]
		  ,tbl0.[host_process_id]
		  ,tbl0.[client_version]
		  ,tbl0.[client_interface_name]
		  ,tbl0.[security_id]
		  ,tbl0.[login_name]
		  ,tbl0.[nt_domain]
		  ,tbl0.[nt_user_name]
		  ,tbl0.[memory_usage]
		  ,tbl0.[total_scheduled_time]
		  ,tbl0.[last_request_start_time]
		  ,tbl0.[last_request_end_time]
		  ,tbl0.[is_user_process]
		  ,tbl0.[original_security_id]
		  ,tbl0.[original_login_name]
		  ,tbl0.[last_successful_logon]
		  ,tbl0.[last_unsuccessful_logon]
		  ,tbl0.[unsuccessful_logons]
		  ,tbl0.[authenticating_database_id]
		  ,tbl0.[sql_handle]
	      ,tbl0.[statement_start_offset]
	      ,tbl0.[statement_end_offset]
	      ,tbl0.[plan_handle]
		  ,tbl0.[dop]
	      ,tbl0.[database_id]
	      ,tbl0.[user_id]
	      ,tbl0.[connection_id]
		  , 1 as [is_blocking_other_session]
	from tbl_group as tg
	inner join tbl0 on tg.blocking_session_id=tbl0.session_id
)
,tbl_res_rec_g as (
	select [plan_handle],
		   [sql_handle],
		   cast([start_time] as date) as [start_time]
	from tbl_res_rec
	group by [plan_handle],
			 [sql_handle],
			 cast([start_time] as date)
)
,tbl_rec_stat_g as (
	select qs.[plan_handle]
		  ,qs.[sql_handle]
		  --,cast(qs.[last_execution_time] as date)	as [last_execution_time]
		  ,min(qs.[creation_time])					as [creation_time]
		  ,max(qs.[execution_count])				as [execution_count]
		  ,max(qs.[total_worker_time])				as [total_worker_time]
		  ,min(qs.[last_worker_time])				as [min_last_worker_time]
		  ,max(qs.[last_worker_time])				as [max_last_worker_time]
		  ,min(qs.[min_worker_time])				as [min_worker_time]
		  ,max(qs.[max_worker_time])				as [max_worker_time]
		  ,max(qs.[total_physical_reads])			as [total_physical_reads]
		  ,min(qs.[last_physical_reads])			as [min_last_physical_reads]
		  ,max(qs.[last_physical_reads])			as [max_last_physical_reads]
		  ,min(qs.[min_physical_reads])				as [min_physical_reads]
		  ,max(qs.[max_physical_reads])				as [max_physical_reads]
		  ,max(qs.[total_logical_writes])			as [total_logical_writes]
		  ,min(qs.[last_logical_writes])			as [min_last_logical_writes]
		  ,max(qs.[last_logical_writes])			as [max_last_logical_writes]
		  ,min(qs.[min_logical_writes])				as [min_logical_writes]
		  ,max(qs.[max_logical_writes])				as [max_logical_writes]
		  ,max(qs.[total_logical_reads])			as [total_logical_reads]
		  ,min(qs.[last_logical_reads])				as [min_last_logical_reads]
		  ,max(qs.[last_logical_reads])				as [max_last_logical_reads]
		  ,min(qs.[min_logical_reads])				as [min_logical_reads]
		  ,max(qs.[max_logical_reads])				as [max_logical_reads]
		  ,max(qs.[total_clr_time])					as [total_clr_time]
		  ,min(qs.[last_clr_time])					as [min_last_clr_time]
		  ,max(qs.[last_clr_time])					as [max_last_clr_time]
		  ,min(qs.[min_clr_time])					as [min_clr_time]
		  ,max(qs.[max_clr_time])					as [max_clr_time]
		  ,max(qs.[total_elapsed_time])				as [total_elapsed_time]
		  ,min(qs.[last_elapsed_time])				as [min_last_elapsed_time]
		  ,max(qs.[last_elapsed_time])				as [max_last_elapsed_time]
		  ,min(qs.[min_elapsed_time])				as [min_elapsed_time]
		  ,max(qs.[max_elapsed_time])				as [max_elapsed_time]
		  ,max(qs.[total_rows])						as [total_rows]
		  ,min(qs.[last_rows])						as [min_last_rows]
		  ,max(qs.[last_rows])						as [max_last_rows]
		  ,min(qs.[min_rows])						as [min_rows]
		  ,max(qs.[max_rows])						as [max_rows]
		  ,max(qs.[total_dop])						as [total_dop]
		  ,min(qs.[last_dop])						as [min_last_dop]
		  ,max(qs.[last_dop])						as [max_last_dop]
		  ,min(qs.[min_dop])						as [min_dop]
		  ,max(qs.[max_dop])						as [max_dop]
		  ,max(qs.[total_grant_kb])					as [total_grant_kb]
		  ,min(qs.[last_grant_kb])					as [min_last_grant_kb]
		  ,max(qs.[last_grant_kb])					as [max_last_grant_kb]
		  ,min(qs.[min_grant_kb])					as [min_grant_kb]
		  ,max(qs.[max_grant_kb])					as [max_grant_kb]
		  ,max(qs.[total_used_grant_kb])			as [total_used_grant_kb]
		  ,min(qs.[last_used_grant_kb])				as [min_last_used_grant_kb]
		  ,max(qs.[last_used_grant_kb])				as [max_last_used_grant_kb]
		  ,min(qs.[min_used_grant_kb])				as [min_used_grant_kb]
		  ,max(qs.[max_used_grant_kb])				as [max_used_grant_kb]
		  ,max(qs.[total_ideal_grant_kb])			as [total_ideal_grant_kb]
		  ,min(qs.[last_ideal_grant_kb])			as [min_last_ideal_grant_kb]
		  ,max(qs.[last_ideal_grant_kb])			as [max_last_ideal_grant_kb]
		  ,min(qs.[min_ideal_grant_kb])				as [min_ideal_grant_kb]
		  ,max(qs.[max_ideal_grant_kb])				as [max_ideal_grant_kb]
		  ,max(qs.[total_reserved_threads])			as [total_reserved_threads]
		  ,min(qs.[last_reserved_threads])			as [min_last_reserved_threads]
		  ,max(qs.[last_reserved_threads])			as [max_last_reserved_threads]
		  ,min(qs.[min_reserved_threads])			as [min_reserved_threads]
		  ,max(qs.[max_reserved_threads])			as [max_reserved_threads]
		  ,max(qs.[total_used_threads])				as [total_used_threads]
		  ,min(qs.[last_used_threads])				as [min_last_used_threads]
		  ,max(qs.[last_used_threads])				as [max_last_used_threads]
		  ,min(qs.[min_used_threads])				as [min_used_threads]
		  ,max(qs.[max_used_threads])				as [max_used_threads]
	from tbl_res_rec_g as t
	inner join sys.dm_exec_query_stats as qs with(readuncommitted) on t.[plan_handle]=qs.[plan_handle] 
																  and t.[sql_handle]=qs.[sql_handle] 
																  and t.[start_time]=cast(qs.[last_execution_time] as date)
	group by qs.[plan_handle]
			,qs.[sql_handle]
			--,qs.[last_execution_time]
)
select t.[session_id] --Сессия
	      ,t.[blocking_session_id] --Сессия, которая явно блокирует сессию [session_id]
		  ,t.[request_id] --Идентификатор запроса. Уникален в контексте сеанса
	      ,t.[start_time] --Метка времени поступления запроса
		  ,DateDiff(second, t.[start_time], GetDate()) as [date_diffSec] --Сколько в сек прошло времени от момента поступления запроса
	      ,t.[status] --Состояние запроса
		  ,t.[status_session] --Состояние сессии
	      ,t.[command] --Тип выполняемой в данный момент команды
		  , COALESCE(
						CAST(NULLIF(t.[total_elapsed_time] / 1000, 0) as BIGINT)
					   ,CASE WHEN (t.[status_session] <> 'running' and isnull(t.[status], '')  <> 'running') 
								THEN  DATEDIFF(ss,0,getdate() - nullif(t.[last_request_end_time], '1900-01-01T00:00:00.000'))
						END
					) as [total_time, sec] --Время всей работы запроса в сек
		  , CAST(NULLIF((CAST(t.[total_elapsed_time] as BIGINT) - CAST(t.[wait_time] AS BIGINT)) / 1000, 0 ) as bigint) as [work_time, sec] --Время работы запроса в сек без учета времени ожиданий
		  , CASE WHEN (t.[status_session] <> 'running' AND ISNULL(t.[status],'') <> 'running') 
		  			THEN  DATEDIFF(ss,0,getdate() - nullif(t.[last_request_end_time], '1900-01-01T00:00:00.000'))
			END as [sleep_time, sec] --Время сна в сек
		  , NULLIF( CAST((t.[logical_reads] + t.[writes]) * 8 / 1024 as numeric(38,2)), 0) as [IO, MB] --операций чтения и записи в МБ
		  , CASE  t.transaction_isolation_level
			WHEN 0 THEN 'Unspecified'
			WHEN 1 THEN 'ReadUncommited'
			WHEN 2 THEN 'ReadCommited'
			WHEN 3 THEN 'Repetable'
			WHEN 4 THEN 'Serializable'
			WHEN 5 THEN 'Snapshot'
			END as [transaction_isolation_level_desc] --уровень изоляции транзакции (расшифровка)
		  ,t.[percent_complete] --Процент завершения работы для следующих команд
		  ,t.[DBName] --БД
		  ,t.[object] --Объект
		  , SUBSTRING(
						t.[TSQL]
					  , t.[statement_start_offset]/2+1
					  ,	(
							CASE WHEN ((t.[statement_start_offset]<0) OR (t.[statement_end_offset]<0))
									THEN DATALENGTH (t.[TSQL])
								 ELSE t.[statement_end_offset]
							END
							- t.[statement_start_offset]
						)/2 +1
					 ) as [CURRENT_REQUEST] --Текущий выполняемый запрос в пакете
	      ,t.[TSQL] --Запрос всего пакета
		  ,t.[QueryPlan] --План всего пакета
	      ,t.[wait_type] --Если запрос в настоящий момент блокирован, в столбце содержится тип ожидания (sys.dm_os_wait_stats)
	      ,t.[login_time] --Время подключения сеанса
		  ,t.[host_name] --Имя клиентской рабочей станции, указанное в сеансе. Для внутреннего сеанса это значение равно NULL
		  ,t.[program_name] --Имя клиентской программы, которая инициировала сеанс. Для внутреннего сеанса это значение равно NULL
		  ,cast(t.[wait_time]/1000 as decimal(18,3)) as [wait_timeSec] --Если запрос в настоящий момент блокирован, в столбце содержится продолжительность текущего ожидания (в секундах)
	      ,t.[wait_time] --Если запрос в настоящий момент блокирован, в столбце содержится продолжительность текущего ожидания (в миллисекундах)
	      ,t.[last_wait_type] --Если запрос был блокирован ранее, в столбце содержится тип последнего ожидания
	      ,t.[wait_resource] --Если запрос в настоящий момент блокирован, в столбце указан ресурс, освобождения которого ожидает запрос
	      ,t.[open_transaction_count] --Число транзакций, открытых для данного запроса
	      ,t.[open_resultset_count] --Число результирующих наборов, открытых для данного запроса
	      ,t.[transaction_id] --Идентификатор транзакции, в которой выполняется запрос
	      ,t.[context_info] --Значение CONTEXT_INFO сеанса
		  ,cast(t.[estimated_completion_time]/1000 as decimal(18,3)) as [estimated_completion_timeSec] --Только для внутреннего использования. Не допускает значение NULL
	      ,t.[estimated_completion_time] --Только для внутреннего использования. Не допускает значение NULL
		  ,cast(t.[cpu_time]/1000 as decimal(18,3)) as [cpu_timeSec] --Время ЦП (в секундах), затраченное на выполнение запроса
	      ,t.[cpu_time] --Время ЦП (в миллисекундах), затраченное на выполнение запроса
		  ,cast(t.[total_elapsed_time]/1000 as decimal(18,3)) as [total_elapsed_timeSec] --Общее время, истекшее с момента поступления запроса (в секундах)
	      ,t.[total_elapsed_time] --Общее время, истекшее с момента поступления запроса (в миллисекундах)
	      ,t.[scheduler_id] --Идентификатор планировщика, который планирует данный запрос
	      ,t.[task_address] --Адрес блока памяти, выделенного для задачи, связанной с этим запросом
	      ,t.[reads] --Число операций чтения, выполненных данным запросом
	      ,t.[writes] --Число операций записи, выполненных данным запросом
	      ,t.[logical_reads] --Число логических операций чтения, выполненных данным запросом
	      ,t.[text_size] --Установка параметра TEXTSIZE для данного запроса
	      ,t.[language] --Установка языка для данного запроса
	      ,t.[date_format] --Установка параметра DATEFORMAT для данного запроса
	      ,t.[date_first] --Установка параметра DATEFIRST для данного запроса
	      ,t.[quoted_identifier] --1 = Параметр QUOTED_IDENTIFIER для запроса включен (ON). В противном случае — 0
	      ,t.[arithabort] --1 = Параметр ARITHABORT для запроса включен (ON). В противном случае — 0
	      ,t.[ansi_null_dflt_on] --1 = Параметр ANSI_NULL_DFLT_ON для запроса включен (ON). В противном случае — 0
	      ,t.[ansi_defaults] --1 = Параметр ANSI_DEFAULTS для запроса включен (ON). В противном случае — 0
	      ,t.[ansi_warnings] --1 = Параметр ANSI_WARNINGS для запроса включен (ON). В противном случае — 0
	      ,t.[ansi_padding] --1 = Параметр ANSI_PADDING для запроса включен (ON)
	      ,t.[ansi_nulls] --1 = Параметр ANSI_NULLS для запроса включен (ON). В противном случае — 0
	      ,t.[concat_null_yields_null] --1 = Параметр CONCAT_NULL_YIELDS_NULL для запроса включен (ON). В противном случае — 0
	      ,t.[transaction_isolation_level] --Уровень изоляции, с которым создана транзакция для данного запроса
		  ,cast(t.[lock_timeout]/1000 as decimal(18,3)) as [lock_timeoutSec] --Время ожидания блокировки для данного запроса (в секундах)
		  ,t.[lock_timeout] --Время ожидания блокировки для данного запроса (в миллисекундах)
	      ,t.[deadlock_priority] --Значение параметра DEADLOCK_PRIORITY для данного запроса
	      ,t.[row_count] --Число строк, возвращенных клиенту по данному запросу
	      ,t.[prev_error] --Последняя ошибка, происшедшая при выполнении запроса
	      ,t.[nest_level] --Текущий уровень вложенности кода, выполняемого для данного запроса
	      ,t.[granted_query_memory] --Число страниц, выделенных для выполнения поступившего запроса (1 страница-это примерно 8 КБ)
	      ,t.[executing_managed_code] --Указывает, выполняет ли данный запрос в настоящее время код объекта среды CLR (например, процедуры, типа или триггера).
									  --Этот флаг установлен в течение всего времени, когда объект среды CLR находится в стеке, даже когда из среды вызывается код Transact-SQL
	      
		  ,t.[group_id]	--Идентификатор группы рабочей нагрузки, которой принадлежит этот запрос
	      ,t.[query_hash] --Двоичное хэш-значение рассчитывается для запроса и используется для идентификации запросов с аналогичной логикой.
						  --Можно использовать хэш запроса для определения использования статистических ресурсов для запросов, которые отличаются только своими литеральными значениями
	      
		  ,t.[query_plan_hash] --Двоичное хэш-значение рассчитывается для плана выполнения запроса и используется для идентификации аналогичных планов выполнения запросов.
							   --Можно использовать хэш плана запроса для нахождения совокупной стоимости запросов со схожими планами выполнения
		  
		  ,t.[most_recent_session_id] --Представляет собой идентификатор сеанса самого последнего запроса, связанного с данным соединением
	      ,t.[connect_time] --Отметка времени установления соединения
	      ,t.[net_transport] --Содержит описание физического транспортного протокола, используемого данным соединением
	      ,t.[protocol_type] --Указывает тип протокола передачи полезных данных
	      ,t.[protocol_version] --Версия протокола доступа к данным, связанного с данным соединением
	      ,t.[endpoint_id] --Идентификатор, описывающий тип соединения. Этот идентификатор endpoint_id может использоваться для запросов к представлению sys.endpoints
	      ,t.[encrypt_option] --Логическое значение, указывающее, разрешено ли шифрование для данного соединения
	      ,t.[auth_scheme] --Указывает схему проверки подлинности (SQL Server или Windows), используемую с данным соединением
	      ,t.[node_affinity] --Идентифицирует узел памяти, которому соответствует данное соединение
	      ,t.[num_reads] --Число пакетов, принятых посредством данного соединения
	      ,t.[num_writes] --Число пакетов, переданных посредством данного соединения
	      ,t.[last_read] --Отметка времени о последнем полученном пакете данных
	      ,t.[last_write] --Отметка времени о последнем отправленном пакете данных
	      ,t.[net_packet_size] --Размер сетевого пакета, используемый для передачи данных
	      ,t.[client_net_address] --Сетевой адрес удаленного клиента
	      ,t.[client_tcp_port] --Номер порта на клиентском компьютере, который используется при осуществлении соединения
	      ,t.[local_net_address] --IP-адрес сервера, с которым установлено данное соединение. Доступен только для соединений, которые в качестве транспорта данных используют протокол TCP
	      ,t.[local_tcp_port] --TCP-порт сервера, если соединение использует протокол TCP
	      ,t.[parent_connection_id] --Идентифицирует первичное соединение, используемое в сеансе MARS
	      ,t.[most_recent_sql_handle] --Дескриптор последнего запроса SQL, выполненного с помощью данного соединения. Постоянно проводится синхронизация между столбцом most_recent_sql_handle и столбцом most_recent_session_id
		  ,t.[host_process_id] --Идентификатор процесса клиентской программы, которая инициировала сеанс. Для внутреннего сеанса это значение равно NULL
		  ,t.[client_version] --Версия TDS-протокола интерфейса, который используется клиентом для подключения к серверу. Для внутреннего сеанса это значение равно NULL
		  ,t.[client_interface_name] --Имя библиотеки или драйвер, используемый клиентом для обмена данными с сервером. Для внутреннего сеанса это значение равно NULL
		  ,t.[security_id] --Идентификатор безопасности Microsoft Windows, связанный с именем входа
		  ,t.[login_name] --SQL Server Имя входа, под которой выполняется текущий сеанс.
						  --Чтобы узнать первоначальное имя входа, с помощью которого был создан сеанс, см. параметр original_login_name.
						  --Может быть SQL Server проверка подлинности имени входа или имени пользователя домена, прошедшего проверку подлинности Windows
		  
		  ,t.[nt_domain] --Домен Windows для клиента, если во время сеанса применяется проверка подлинности Windows или доверительное соединение.
						 --Для внутренних сеансов и пользователей, не принадлежащих к домену, это значение равно NULL
		  
		  ,t.[nt_user_name] --Имя пользователя Windows для клиента, если во время сеанса используется проверка подлинности Windows или доверительное соединение.
							--Для внутренних сеансов и пользователей, не принадлежащих к домену, это значение равно NULL
		  
		  ,t.[memory_usage] --Количество 8-килобайтовых страниц памяти, используемых данным сеансом
		  ,t.[total_scheduled_time] --Общее время, назначенное данному сеансу (включая его вложенные запросы) для исполнения, в миллисекундах
		  ,t.[last_request_start_time] --Время, когда начался последний запрос данного сеанса. Это может быть запрос, выполняющийся в данный момент
		  ,t.[last_request_end_time] --Время завершения последнего запроса в рамках данного сеанса
		  ,t.[is_user_process] --0, если сеанс является системным. В противном случае значение равно 1
		  ,t.[original_security_id] --Microsoft Идентификатор безопасности Windows, связанный с параметром original_login_name
		  ,t.[original_login_name] --SQL Server Имя входа, которую использует клиент создал данный сеанс.
								   --Это может быть имя входа SQL Server, прошедшее проверку подлинности, имя пользователя домена Windows, 
								   --прошедшее проверку подлинности, или пользователь автономной базы данных.
								   --Обратите внимание, что после первоначального соединения для сеанса может быть выполнено много неявных или явных переключений контекста.
								   --Например если EXECUTE AS используется
		  
		  ,t.[last_successful_logon] --Время последнего успешного входа в систему для имени original_login_name до запуска текущего сеанса
		  ,t.[last_unsuccessful_logon] --Время последнего неуспешного входа в систему для имени original_login_name до запуска текущего сеанса
		  ,t.[unsuccessful_logons] --Число неуспешных попыток входа в систему для имени original_login_name между временем last_successful_logon и временем login_time
		  ,t.[authenticating_database_id] --Идентификатор базы данных, выполняющей проверку подлинности участника.
										  --Для имен входа это значение будет равно 0.
										  --Для пользователей автономной базы данных это значение будет содержать идентификатор автономной базы данных
		  
		  ,t.[sql_handle] --Хэш-карта текста SQL-запроса
	      ,t.[statement_start_offset] --Количество символов в выполняемом в настоящий момент пакете или хранимой процедуре, в которой запущена текущая инструкция.
									  --Может применяться вместе с функциями динамического управления sql_handle, statement_end_offset и sys.dm_exec_sql_text
									  --для извлечения исполняемой в настоящий момент инструкции по запросу
	      
		  ,t.[statement_end_offset] --Количество символов в выполняемом в настоящий момент пакете или хранимой процедуре, в которой завершилась текущая инструкция.
									--Может применяться вместе с функциями динамического управления sql_handle, statement_end_offset и sys.dm_exec_sql_text
									--для извлечения исполняемой в настоящий момент инструкции по запросу
	      
		  ,t.[plan_handle] --Хэш-карта плана выполнения SQL
	      ,t.[database_id] --Идентификатор базы данных, к которой выполняется запрос
	      ,t.[user_id] --Идентификатор пользователя, отправившего данный запрос
	      ,t.[connection_id] --Идентификатор соединения, по которому поступил запрос
		  ,t.[is_blocking_other_session] --1-сессия явно блокирует другие сессии, 0-сессия явно не блокирует другие сессии
		  ,coalesce(t.[dop], mg.[dop]) as [dop] --Степень параллелизма запроса
		  ,mg.[request_time] --Дата и время обращения запроса за предоставлением памяти
		  ,mg.[grant_time] --Дата и время, когда запросу была предоставлена память. Возвращает значение NULL, если память еще не была предоставлена
		  ,mg.[requested_memory_kb] --Общий объем запрошенной памяти в килобайтах
		  ,mg.[granted_memory_kb] --Общий объем фактически предоставленной памяти в килобайтах.
								  --Может быть значение NULL, если память еще не была предоставлена.
								  --Обычно это значение должно быть одинаковым с requested_memory_kb.
								  --Для создания индекса сервер может разрешить дополнительное предоставление по требованию памяти,
								  --объем которой выходит за рамки изначально предоставленной памяти
		  
		  ,mg.[required_memory_kb] --Минимальный объем памяти в килобайтах (КБ), необходимый для выполнения данного запроса.
								   --Значение requested_memory_kb равно этому объему или больше его
		  
		  ,mg.[used_memory_kb] --Используемый в данный момент объем физической памяти (в килобайтах)
		  ,mg.[max_used_memory_kb] --Максимальный объем используемой до данного момента физической памяти в килобайтах
		  ,mg.[query_cost] --Ожидаемая стоимость запроса
		  ,mg.[timeout_sec] --Время ожидания данного запроса в секундах до отказа от обращения за предоставлением памяти
		  ,mg.[resource_semaphore_id] --Неуникальный идентификатор семафора ресурса, которого ожидает данный запрос
		  ,mg.[queue_id] --Идентификатор ожидающей очереди, в которой данный запрос ожидает предоставления памяти.
						 --Значение NULL, если память уже предоставлена
		  
		  ,mg.[wait_order] --Последовательный порядок ожидающих запросов в указанной очереди queue_id.
						   --Это значение может изменяться для заданного запроса, если другие запросы отказываются от предоставления памяти или получают ее.
						   --Значение NULL, если память уже предоставлена
		  
		  ,mg.[is_next_candidate] --Является следующим кандидатом на предоставление памяти (1 = да, 0 = нет, NULL = память уже предоставлена)
		  ,mg.[wait_time_ms] --Время ожидания в миллисекундах. Значение NULL, если память уже предоставлена
		  ,mg.[pool_id] --Идентификатор пула ресурсов, к которому принадлежит данная группа рабочей нагрузки
		  ,mg.[is_small] --Значение 1 означает, что для данной операции предоставления памяти используется малый семафор ресурса.
						 --Значение 0 означает использование обычного семафора
		  
		  ,mg.[ideal_memory_kb] --Объем, в килобайтах (КБ), предоставленной памяти, необходимый для размещения всех данных в физической памяти.
								--Основывается на оценке количества элементов
		  
		  ,mg.[reserved_worker_count] --Число рабочих процессов, зарезервированной с помощью параллельных запросов, а также число основных рабочих процессов, используемых всеми запросами
		  ,mg.[used_worker_count] --Число рабочих процессов, используемых параллельных запросов
		  ,mg.[max_used_worker_count] --???
		  ,mg.[reserved_node_bitmap] --???
		  ,pl.[bucketid] --Идентификатор сегмента хэша, в который кэшируется запись.
						 --Значение указывает диапазон от 0 до значения размера хэш-таблицы для типа кэша.
						 --Для кэшей SQL Plans и Object Plans размер хэш-таблицы может достигать 10007 на 32-разрядных версиях систем и 40009 — на 64-разрядных.
						 --Для кэша Bound Trees размер хэш-таблицы может достигать 1009 на 32-разрядных версиях систем и 4001 на 64-разрядных.
						 --Для кэша расширенных хранимых процедур размер хэш-таблицы может достигать 127 на 32-разрядных и 64-разрядных версиях систем
		  
		  ,pl.[refcounts] --Число объектов кэша, ссылающихся на данный объект кэша.
						  --Значение refcounts для записи должно быть не меньше 1, чтобы размещаться в кэше
		  
		  ,pl.[usecounts] --Количество повторений поиска объекта кэша.
						  --Остается без увеличения, если параметризованные запросы обнаруживают план в кэше.
						  --Может быть увеличен несколько раз при использовании инструкции showplan
		  
		  ,pl.[size_in_bytes] --Число байтов, занимаемых объектом кэша
		  ,pl.[memory_object_address] --Адрес памяти кэшированной записи.
									  --Это значение можно использовать с представлением sys.dm_os_memory_objects,
									  --чтобы проанализировать распределение памяти кэшированного плана, 
									  --и с представлением sys.dm_os_memory_cache_entries для определения затрат на кэширование записи
		  
		  ,pl.[cacheobjtype] --Тип объекта в кэше. Значение может быть одним из следующих
		  ,pl.[objtype] --Тип объекта. Значение может быть одним из следующих
		  ,pl.[parent_plan_handle] --Родительский план
		  
		  --данные из sys.dm_exec_query_stats брались за сутки, в которых была пара (запрос, план)
		  ,qs.[creation_time] --Время компиляции плана
		  ,qs.[execution_count] --Количество выполнений плана с момента последней компиляции
		  ,qs.[total_worker_time] --Общее время ЦП, затраченное на выполнение плана с момента компиляции, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[min_last_worker_time] --Минимальное время ЦП, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[max_last_worker_time] --Максимальное время ЦП, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[min_worker_time] --Минимальное время ЦП, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[max_worker_time] --Максимальное время ЦП, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[total_physical_reads] --Общее количество операций физического считывания при выполнении плана с момента его компиляции.
									 --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_last_physical_reads] --Минимальное количество операций физического считывания за время последнего выполнения плана.
										--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_last_physical_reads] --Максимальное количество операций физического считывания за время последнего выполнения плана.
										--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_physical_reads] --Минимальное количество операций физического считывания за одно выполнение плана.
								   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_physical_reads] --Максимальное количество операций физического считывания за одно выполнение плана.
								   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[total_logical_writes] --Общее количество операций логической записи при выполнении плана с момента его компиляции.
									 --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_last_logical_writes] --Минимальное количество страниц в буферном пуле, загрязненных во время последнего выполнения плана.
										--Если страница уже является «грязной» (т. е. измененной), операции записи не учитываются.
										--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_last_logical_writes] --Максимальное количество страниц в буферном пуле, загрязненных во время последнего выполнения плана.
										--Если страница уже является «грязной» (т. е. измененной), операции записи не учитываются.
										--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_logical_writes] --Минимальное количество операций логической записи за одно выполнение плана.
								   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_logical_writes] --Максимальное количество операций логической записи за одно выполнение плана.
								   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[total_logical_reads] --Общее количество операций логического считывания при выполнении плана с момента его компиляции.
									--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_last_logical_reads] --Минимальное количество операций логического считывания за время последнего выполнения плана.
									   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_last_logical_reads] --Максимальное количество операций логического считывания за время последнего выполнения плана.
									   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[min_logical_reads]	   --Минимальное количество операций логического считывания за одно выполнение плана.
									   --Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[max_logical_reads]	--Максимальное количество операций логического считывания за одно выполнение плана.
									--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
		  
		  ,qs.[total_clr_time]	--Время, в микросекундах (но с точностью до миллисекунды),
								--внутри Microsoft .NET Framework общеязыковая среда выполнения (CLR) объекты при выполнении плана с момента его компиляции.
								--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
		  
		  ,qs.[min_last_clr_time] --Минимальное время, в микросекундах (но с точностью до миллисекунды),
								  --затраченное внутри .NET Framework объекты среды CLR во время последнего выполнения плана.
								  --Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
		  
		  ,qs.[max_last_clr_time] --Максимальное время, в микросекундах (но с точностью до миллисекунды),
								  --затраченное внутри .NET Framework объекты среды CLR во время последнего выполнения плана.
								  --Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
		  
		  ,qs.[min_clr_time] --Минимальное время, когда-либо затраченное на выполнение плана внутри объектов .NET Framework среды CLR,
							 --в микросекундах (но с точностью до миллисекунды).
							 --Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
		  
		  ,qs.[max_clr_time] --Максимальное время, когда-либо затраченное на выполнение плана внутри среды CLR .NET Framework,
							 --в микросекундах (но с точностью до миллисекунды).
							 --Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
		  
		  --,qs.[total_elapsed_time] --Общее время, затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[min_last_elapsed_time] --Минимальное время, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[max_last_elapsed_time] --Максимальное время, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[min_elapsed_time] --Минимальное время, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[max_elapsed_time] --Максимальное время, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
		  ,qs.[total_rows] --Общее число строк, возвращаемых запросом. Не может иметь значение null.
						   --Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
		  
		  ,qs.[min_last_rows] --Минимальное число строк, возвращенных последним выполнением запроса. Не может иметь значение null.
							  --Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
		  
		  ,qs.[max_last_rows] --Максимальное число строк, возвращенных последним выполнением запроса. Не может иметь значение null.
							  --Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
		  
		  ,qs.[min_rows] --Минимальное количество строк, когда-либо возвращенных по запросу во время выполнения один
						 --Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
		  
		  ,qs.[max_rows] --Максимальное число строк, когда-либо возвращенных по запросу во время выполнения один
						 --Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
		  
		  ,qs.[total_dop] --Общую сумму по степени параллелизма плана используется с момента его компиляции.
						  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_dop] --Минимальная степень параллелизма, если время последнего выполнения плана.
							 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_dop] --Максимальная степень параллелизма, если время последнего выполнения плана.
							 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_dop] --Минимальная степень параллелизма этот план когда-либо используется во время одного выполнения.
						--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_dop] --Максимальная степень параллелизма этот план когда-либо используется во время одного выполнения.
						--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[total_grant_kb] --Общий объем зарезервированной памяти в КБ предоставить этот план, полученных с момента его компиляции.
							   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_grant_kb] --Минимальный объем зарезервированной памяти предоставляет в КБ, когда время последнего выполнения плана.
								  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_grant_kb] --Максимальный объем зарезервированной памяти предоставляет в КБ, когда время последнего выполнения плана.
								  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_grant_kb] --Минимальный объем зарезервированной памяти в КБ предоставить никогда не получено в ходе одного выполнения плана.
							 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_grant_kb] --Максимальный объем зарезервированной памяти в КБ предоставить никогда не получено в ходе одного выполнения плана.
							 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[total_used_grant_kb] --Общий объем зарезервированной памяти в КБ предоставить этот план, используемый с момента его компиляции.
									--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_used_grant_kb] --Минимальная сумма предоставления используемой памяти в КБ, если время последнего выполнения плана.
									   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_used_grant_kb] --Максимальная сумма предоставления используемой памяти в КБ, если время последнего выполнения плана.
									   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_used_grant_kb] --Минимальный объем используемой памяти в КБ предоставить никогда не используется при выполнении одного плана.
								  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_used_grant_kb] --Максимальный объем используемой памяти в КБ предоставить никогда не используется при выполнении одного плана.
								  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[total_ideal_grant_kb] --Общий объем идеальный память в КБ, оценка плана с момента его компиляции.
									 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_ideal_grant_kb] --Минимальный объем памяти, идеальным предоставляет в КБ, когда время последнего выполнения плана.
										--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_ideal_grant_kb] --Максимальный объем памяти, идеальным предоставляет в КБ, когда время последнего выполнения плана.
										--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_ideal_grant_kb] --Минимальный объем памяти идеальный предоставления в этот план когда-либо оценка во время выполнения один КБ.
								   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_ideal_grant_kb] --Максимальный объем памяти идеальный предоставления в этот план когда-либо оценка во время выполнения один КБ.
								   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[total_reserved_threads] --Общая сумма по зарезервированным параллельного потоков этот план когда-либо использовавшегося с момента его компиляции.
									   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_reserved_threads] --Минимальное число зарезервированных параллельных потоков, когда время последнего выполнения плана.
										  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_reserved_threads] --Максимальное число зарезервированных параллельных потоков, когда время последнего выполнения плана.
										  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_reserved_threads] --Минимальное число зарезервированных параллельного потоков, когда-либо использовать при выполнении одного плана.
									 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_reserved_threads] --Максимальное число зарезервированных параллельного потоков никогда не используется при выполнении одного плана.
									 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[total_used_threads] --Общая сумма используется параллельных потоков этот план когда-либо использовавшегося с момента его компиляции.
								   --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_last_used_threads] --Минимальное число используемых параллельных потоков, когда время последнего выполнения плана.
									  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_last_used_threads] --Максимальное число используемых параллельных потоков, когда время последнего выполнения плана.
									  --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[min_used_threads] --Минимальное число используемых параллельных потоков, при выполнении одного плана использовали.
								 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
		  
		  ,qs.[max_used_threads] --Максимальное число используемых параллельных потоков, при выполнении одного плана использовали.
								 --Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
from tbl_res_rec as t
left outer join sys.dm_exec_query_memory_grants as mg on t.[plan_handle]=mg.[plan_handle] and t.[sql_handle]=mg.[sql_handle]
left outer join sys.dm_exec_cached_plans as pl on t.[plan_handle]=pl.[plan_handle]
left outer join tbl_rec_stat_g as qs on t.[plan_handle]=qs.[plan_handle] and t.[sql_handle]=qs.[sql_handle] --and qs.[last_execution_time]=cast(t.[start_time] as date);

I would also like to remind you that based on the collected statistics, you can identify the most resource-intensive queries:
Code

/*
creation_time - Время, когда запрос был скомпилирован. Поскольку при старте сервера кэш пустой, данное время всегда больше либо равно моменту запуска сервиса. Если время, указанное в этом столбце позже, чем предполагаемое (первое использование процедуры), это говорит о том, что запрос по тем или иным причинам был рекомпилирован.
last_execution_time - Момент фактического последнего выполнения запроса.
execution_count - Сколько раз запрос был выполнен с момента компиляции
Количество выполнений позволяет найти ошибки в алгоритмах - часто в наиболее выполняемых запросах оказываются те, которые находятся внутри каких-либо циклов однако могут быть выполнены перед самим циклом один раз. Например, получение каких-либо параметров из базы данных, не меняющихся внутри цикла.
CPU - Суммарное время использования процессора в миллисекундах. Если запрос обрабатывается параллельно, то это время может превысить общее время выполнения запроса, поскольку суммируется время использования запроса каждым ядром. Во время использования процессора включается только фактическая нагрузка на ядра, в нее не входят ожидания каких-либо ресурсов.
Очевидно, что данный показатель позволяет выявлять запросы, наиболее сильно загружающие процессор.
AvgCPUTime - Средняя загрузка процессора на один запрос. 
TotDuration - Общее время выполнения запроса, в миллисекундах.
Данный параметр может быть использован для поиска тех запросов, которые, независимо от причины выполняются "наиболее долго". Если общее время выполнения запроса существенно ниже времени CPU (с поправкой на параллелизм) - это говорит о том, что при выполнения запроса были ожидания каких-либо ресурсов. В большинстве случаев это связано с дисковой активностью или блокировками, но также это может быть сетевой интерфейс или другой ресурс. 
Полный список типов ожиданий можно посмотреть в описании представления sys.dm_os_wait_stats.
AvgDur - Среднее время выполнения запроса в миллисекундах.
Reads - Общее количество чтений.
Это пожалуй лучший агрегатный показатель, позволяющий выявить наиболее нагружающие сервер запросы.
Логическое чтение - это разовое обращение к странице данных, физические чтения не учитываются.
В рамках выполнения одного запроса, могут происходить неоднократные обращения к одной и той же странице.
Чем больше обращений к страницам, тем больше требуется дисковых чтений, памяти и, если речь идет о повторных обращениях, большее время требуется удерживать страницы в памяти.
Writes - Общее количество изменений страниц данных.
Характеризует то, как запрос "нагружает" дисковую систему операциями записи.
Следует помнить, что этот показатель может быть больше 0 не только у тех запросов, которые явно меняют данные, но также и у тех, которые сохраняют промежуточные данные в tempdb.
AggIO - Общее количество логических операций ввода-вывода (суммарно)
Как правило, количество логических чтений на порядки превышает количество операций записи, поэтому этот показатель сам по себе для анализа применим в редких случаях.
AvgIO - Среднее количество логических дисковых операций на одно выполнение запроса.
Значение данного показателя можно анализировать из следующих соображений:
Одна страница данных - это 8192 байта. Можно получить среднее количество байт данных, "обрабатываемых" данным запросом. Если этот объем превышает реальное количество данных, которые обрабатывает запрос (суммарный объем данных в используемых в запросе таблицах), это говорит о том, что был выбран заведомо плохой план выполнения и требуется заняться оптимизацией данного запроса.
Я встречал случай, когда один запрос делал количество обращений, эквивалентных объему в 5Тб, при этом общий объем данных в это БД был 300Гб, а объем данных в таблицах, задействованных в запросе не превышал 10Гб.
В общем можно описать одну причину такого поведения сервера - вместо использования индекса сервер предпочитает сканировать таблицу или наоборот.
Если объем логических чтений в разы превосходит общие объем данных, то это вызвано повторным обращениям к одним и тем же страницам данных. Помимо того, что в одном запросе таблица может быть использована несколько раз, к одним и тем же страницам сервер обращается например в случаях, когда используется индекс и по результатам поиска по нему, найденные некоторые строки данных лежат на одной и той же странице. Конечно, в таком случае предпочтительным могло бы быть сканирование таблицы - в этом случае сервер обращался бы к каждой странице данных только один раз. Однако этому часто мешают... попытки оптимизации запросов, когда разработчик явно указывает, какой индекс или тип соединения должен быть использован.
Обратный случай - вместо использования индекса было выбрано сканирование таблицы. Как правило, это связано с тем, что статистика устарела и требуется её обновление. Однако и в этом случае причиной неудачно выбранного плана вполне могут оказаться подсказки оптимизатору запросов.
query_text - Текст самого запроса
database_name - Имя базы данных, в находится объект, содержащий запрос. NULL для системных процедур
object_name - Имя объекта (процедуры или функции), содержащего запрос.
*/
with s as (
	select  creation_time,
			last_execution_time,
			execution_count,
			total_worker_time/1000 as CPU,
			convert(money, (total_worker_time))/(execution_count*1000)as [AvgCPUTime],
			qs.total_elapsed_time/1000 as TotDuration,
			convert(money, (qs.total_elapsed_time))/(execution_count*1000)as [AvgDur],
			total_logical_reads as [Reads],
			total_logical_writes as [Writes],
			total_logical_reads+total_logical_writes as [AggIO],
			convert(money, (total_logical_reads+total_logical_writes)/(execution_count + 0.0))as [AvgIO],
			[sql_handle],
			plan_handle,
			statement_start_offset,
			statement_end_offset
	from sys.dm_exec_query_stats as qs with(readuncommitted)
	where convert(money, (qs.total_elapsed_time))/(execution_count*1000)>=100 --выполнялся запрос не менее 100 мс
)
select
	s.creation_time,
	s.last_execution_time,
	s.execution_count,
	s.CPU,
	s.[AvgCPUTime],
	s.TotDuration,
	s.[AvgDur],
	s.[Reads],
	s.[Writes],
	s.[AggIO],
	s.[AvgIO],
	--st.text as query_text,
	case 
		when sql_handle IS NULL then ' '
		else(substring(st.text,(s.statement_start_offset+2)/2,(
			case
				when s.statement_end_offset =-1 then len(convert(nvarchar(MAX),st.text))*2      
				else s.statement_end_offset    
			end - s.statement_start_offset)/2  ))
	end as query_text,
	db_name(st.dbid) as database_name,
	object_schema_name(st.objectid, st.dbid)+'.'+object_name(st.objectid, st.dbid) as [object_name],
	sp.[query_plan],
	s.[sql_handle],
	s.plan_handle
from s
cross apply sys.dm_exec_sql_text(s.[sql_handle]) as st
cross apply sys.dm_exec_query_plan(s.[plan_handle]) as sp

It is also possible to write it for MySQL. For that, you need to install mysql-connector-net and then write code similar to this:
Code for pending requests

#Задаем переменные для подключение к MySQL и само подключение
[string]$sMySQLUserName = 'UserName'
[string]$sMySQLPW = 'UserPassword'
[string]$sMySQLDB = 'db'
[string]$sMySQLHost = 'IP-address'
[void][System.Reflection.Assembly]::LoadWithPartialName("MySql.Data");
[string]$sConnectionString = "server="+$sMySQLHost+";port=3306;uid=" + $sMySQLUserName + ";pwd="+"'" + $sMySQLPW +"'"+ ";database="+$sMySQLDB;

#Open a Database connection
$oConnection = New-Object MySql.Data.MySqlClient.MySqlConnection($sConnectionString)
$Error.Clear()
try
{
    $oConnection.Open()
}
catch
{
    write-warning ("Could not open a connection to Database $sMySQLDB on Host $sMySQLHost. Error: "+$Error[0].ToString())
}

#The first query
# Get an instance of all objects need for a SELECT query. The Command object
$oMYSQLCommand = New-Object MySql.Data.MySqlClient.MySqlCommand;
# DataAdapter Object
$oMYSQLDataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter;
# And the DataSet Object
$oMYSQLDataSet = New-Object System.Data.DataSet;
# Assign the established MySQL connection
$oMYSQLCommand.Connection=$oConnection;
# Define a SELECT query
$oMYSQLCommand.CommandText='query';

$oMYSQLDataAdapter.SelectCommand=$oMYSQLCommand;
# Execute the query
$count=$oMYSQLDataAdapter.Fill($oMYSQLDataSet, "data");

$result = $oMYSQLDataSet.Tables[0].Rows[0]["Count"];

write-host $result;

Result

This article discussed an example of performance counters (data elements) in Zabbix. This approach allows administrators to be notified of various issues in real time or after a certain period. Thus, this approach helps minimize the occurrence of critical problems in the future and prevent the database and server from stopping, which in turn protects production from workflow interruptions.
Previous article: Scheduled maintenance for the database of the information system 24×7 in MS SQL Server

Sources:

» Zabbix 3.4
» Performance counters
» Performance Center for Azure SQL Database and SQL Server Database Engine
» SQL lifestyle
» SQLSkills
» TechNet Microsoft
» Analyzing memory usage
» Performance analysis
» SQL documentation
» Notes on Windows

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster