Poniżej przedstawiam sposób w jaki można wyciągnąć z SQL Server listę najbardziej kosztownych zapytań T-SQL. Zapytanie to zwraca do czterej list w podziale na kategorie (kryteria) tego czego szukamy:

  • Frequently ran query
  • High Disk Reading query
  • High CPU query
  • Long Running query

Gdy znajdziemy już na liście interesujące nas zapytanie można przejść do ostatniej kolumny tego zapytania, otworzyć plan wykonania i rozpocząć analizę i dostrajanie zapytania.

W zapytaniu tym ustawiamy odpowiednie wartości do uzyskania kategorii oraz możemy określić ile najcięższych zapytań chcemy mieć na liście. Definiujemy to na początku skryptu.

DECLARE @frq bit = 0, -- Frequently ran query
        @hdr bit = 1, -- High Disk Reading query
        @hc  bit = 0, -- High CPU query 
        @lr  bit = 1  -- Long Running query

DECLARE @nTop int = 5

Poniżej został przedstawiony cały skrypt. Powodzenia 😉

/*
-- List most expensive queries
-- Author: Dariusz Brejnak

*/

DECLARE @frq bit = 0, -- Frequently ran query
        @hdr bit = 1, -- High Disk Reading query
        @hc  bit = 0, -- High CPU query 
        @lr  bit = 1  -- Long Running query

DECLARE @nTop int = 5

DECLARE @expquery INT 
SET @expquery = POWER(2*@frq,1)  -- 2
              + POWER(2*@hdr,2)  -- 4
              + POWER(2*@hc,3)   -- 8
              + POWER(2*@lr,4)  -- 16

PRINT @expquery 
IF ( (2 & @expquery) = 2 )   PRINT 'Frequently ran query' 
IF ( (4 & @expquery) = 4 )   PRINT 'High Disk Reading query' 
IF ( (8 & @expquery) = 8 )   PRINT 'High CPU query' 
IF ( (16 & @expquery) = 16 ) PRINT 'Long Running query' 



;WITH MostExpensive 
AS
(
SELECT 
  [Execution Count]				= qs.execution_count
, [Total Logical Reads (MB)]	= (qs.total_logical_reads)*8/1024.0
, [Avg Logical Reads (MB)]		= (qs.total_logical_reads/qs.execution_count)*8/1024.0 
, [Total Worker Time (ms)]		= (qs.total_worker_time)/1000.0
, [Avg Worker Time (ms)]		= (qs.total_worker_time/qs.execution_count)/1000.0 
, [Total Elapsed Time (ms)]		= (qs.total_elapsed_time)/1000.0 
, [Avg Elapsed Time (ms)]		= (qs.total_elapsed_time/qs.execution_count)/1000.0
, [Creation Time]				= qs.creation_time  
, [Complete Query Text]			= t.text 
, [Query Plan]					= qp.query_plan  
FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp
WHERE t.dbid = DB_ID() 
)
, frq as
(
SELECT TOP(@nTop) 
des = 'frequently ran query', *
FROM MostExpensive
ORDER BY [Execution Count] DESC -- Frequently ran query
)
, hdr as
(
SELECT TOP(@nTop) 
des = 'High Disk Reading query', *
FROM MostExpensive
ORDER BY [Total Logical Reads (MB)] DESC -- High Disk Reading query
)
, hc as
(
SELECT TOP(@nTop) 
des = 'High CPU query', *
FROM MostExpensive
ORDER BY [Avg Worker Time (ms)] DESC -- High CPU query
)
, lr as
(
SELECT TOP(@nTop) 
des = 'Long Running query', *
FROM MostExpensive
ORDER BY [Avg Elapsed Time (ms)] DESC -- Long Running query
)
SELECT * FROM frq WHERE ( (2 & @expquery) = 2 )
UNION ALL
SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL WHERE ( (2 & @expquery) = 2 )
UNION ALL
SELECT * FROM hdr WHERE ( (4 & @expquery) = 4 )
UNION ALL
SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL WHERE ( (4 & @expquery) = 4 )
UNION ALL
SELECT * FROM hc WHERE ( (8 & @expquery) = 8 )
UNION ALL
SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL WHERE ( (8 & @expquery) = 8 )
UNION ALL
SELECT * FROM lr WHERE ( (16 & @expquery) = 16 )
OPTION (RECOMPILE)



Dariusz Brejnak

Od prawie trzydziestu lat jest pasjonatem informatyki, a zwłaszcza dziedzin dotyczących baz danych, hurtowni danych oraz ogólnie rozumianej tematyki BI. Jego druga pasja to fotografia http://dariuszbrejnak.pl