Recherche des requêtes et procédures longues

Cette requête multibase recherche les procédures et les requêtes dépassant un certain seuil (plus de 500 ms pour les procédures et plus de 250 pour les requêtes)


SELECT 'PROCEDURE' AS SQL_TYPE, DB_NAME(database_id) AS base, max_worker_time,  
       total_worker_time / CAST(execution_count AS FLOAT) AS AVG_TIME,
       COALESCE('mephisto..' + om.name,  
                'galeo..' + og.name,  
                'gescom..' + oc.name,
                'prospects..' + op.name,  
                'aveilla..' + oa.name,
                'master..' + osm.name,
                'msdb..' + oss.name,
                'distribution..' + osd.name,
                'tempdb..' + ost.name)  AS CODE,
       '500000' AS DURE_PLUS_DE_MICROSECONDES          
FROM   sys.dm_exec_procedure_stats AS ps
       LEFT OUTER JOIN Base1.sys.objects AS om
            ON ps.object_id = om.object_id AND ps.database_id = DB_ID('Base1')  
       LEFT OUTER JOIN Base2.sys.objects AS og
            ON ps.object_id = og.object_id AND ps.database_id = DB_ID('Base2')  
       LEFT OUTER JOIN Base3.sys.objects AS oc
            ON ps.object_id = oc.object_id AND ps.database_id = DB_ID('Base3')  
 
--> remplacer Base1, base2, Base3... par le noms de toutes vos base de production....
 
WHERE   total_worker_time / CAST(execution_count AS FLOAT) > 500000
UNION ALL
SELECT 'REQUETE' AS SQL_TYPE, NULL AS base, max_worker_time,
       total_worker_time / CAST(execution_count AS FLOAT) AS AVG_TIME,  
       text,
       '250000' AS DURE_PLUS_DE_MICROSECONDES  
FROM   sys.dm_exec_query_stats AS ps
       CROSS APPLY sys.dm_exec_sql_text(sql_handle)
WHERE   total_worker_time / CAST(execution_count AS FLOAT) > 250000
ORDER BY AVG_TIME DESC

Partant de cette requête on peut trouver par exemple les procédures et les requêtes les plus erratiques , c’est à dire celle dont l’écart entre durée min et max est d’au moins 10 fois :


-- récupère les procédures, requêtes et trigers dont l'écart entre durée min et max est d'au moins 10 fois
WITH T AS
(
SELECT 'PROCEDURE' AS SQL_TYPE,  
       COALESCE(DB_NAME(database_id), 'MSSQLsystemResource') AS BASE, database_id,
       min_worker_time, max_worker_time,  
       total_worker_time / CAST(execution_count AS FLOAT) AS AVG_TIME,
       COALESCE('Base1..' + b1.name,  
                'Base2..' + b2.name,  
                'Base3..' + b3.name,
                ...
                'master..' + osm.name,
                'msdb..' + oss.name,
                'tempdb..' + ost.name,
                'resource..' + osr.name)  AS CODE, ps.object_id ,
       max_worker_time - min_worker_time AS ECART_MUS,
       max_worker_time / CAST(min_worker_time AS DECIMAL(16,2)) AS ECART_FOIS          
FROM   sys.dm_exec_procedure_stats AS ps
       LEFT OUTER JOIN Base1.sys.objects AS b1
            ON ps.object_id = b1.object_id AND ps.database_id = DB_ID('Base1')  
       LEFT OUTER JOIN Base2.sys.objects AS b2
            ON ps.object_id = b2.object_id AND ps.database_id = DB_ID('Base2')  
       LEFT OUTER JOIN Base3.sys.objects AS b3
            ON ps.object_id = b3.object_id AND ps.database_id = DB_ID('Base3')  
       ...
       LEFT OUTER JOIN master.sys.objects AS osm
            ON ps.object_id = osm.object_id AND ps.database_id = DB_ID('master')  
       LEFT OUTER JOIN msdb.sys.objects AS oss
            ON ps.object_id = oss.object_id AND ps.database_id = DB_ID('msdb')  
       LEFT OUTER JOIN tempdb.sys.objects AS ost
            ON ps.object_id = ost.object_id AND ps.database_id = DB_ID('tempdb')  
       LEFT OUTER JOIN master.sys.objects AS osr
            ON ps.object_id = osr.object_id AND ps.database_id = 32767            
WHERE  max_worker_time - min_worker_time >= 10 *  total_worker_time / CAST(execution_count AS FLOAT)
UNION ALL
SELECT 'REQUETE' AS SQL_TYPE, NULL AS BASE, NULL, min_worker_time, max_worker_time,  
       total_worker_time / CAST(execution_count AS FLOAT) AS AVG_TIME,  
       text, NULL ,
       max_worker_time - min_worker_time AS ECART_MUS,
       max_worker_time / CAST(min_worker_time AS DECIMAL(16,2)) AS ECART_FOIS
FROM   sys.dm_exec_query_stats AS ps
       CROSS APPLY sys.dm_exec_sql_text(sql_handle)
WHERE  max_worker_time - min_worker_time >= 10 *  total_worker_time / CAST(execution_count AS FLOAT)
UNION ALL
SELECT 'DÉCLENCHEUR' AS SQL_TYPE, COALESCE(DB_NAME(database_id), 'MSSQLsystemResource') AS BASE, database_id,
       min_worker_time, max_worker_time,  
       total_worker_time / CAST(execution_count AS FLOAT) AS AVG_TIME,  
       COALESCE('Base1..' + b1.name,  
                'Base2..' + b2.name,  
                'Base3..' + b3.name,
                ...  
                'master..' + osm.name,
                'msdb..' + oss.name,
                'tempdb..' + ost.name,
                'resource..' + osr.name)  AS CODE, ts.object_id ,
       max_worker_time - min_worker_time AS ECART_MUS,
       max_worker_time / CAST(min_worker_time AS DECIMAL(16,2)) AS ECART_FOIS
FROM   sys.dm_exec_trigger_stats as ts
       LEFT OUTER JOIN Base1.sys.objects AS b1
            ON ts.object_id = b1.object_id AND ts.database_id = DB_ID('Base1')  
       LEFT OUTER JOIN Base2.sys.objects AS b2
            ON ts.object_id = b2.object_id AND ts.database_id = DB_ID('Base2')  
       LEFT OUTER JOIN Base3.sys.objects AS b3
            ON ts.object_id = b3.object_id AND ts.database_id = DB_ID('Base3')  
       ...
       LEFT OUTER JOIN master.sys.objects AS osm
            ON ps.object_id = osm.object_id AND ps.database_id = DB_ID('master')  
       LEFT OUTER JOIN msdb.sys.objects AS oss
            ON ts.object_id = oss.object_id AND ts.database_id = DB_ID('msdb')  
       LEFT OUTER JOIN distribution.sys.objects AS osd
            ON ts.object_id = ost.object_id AND ts.database_id = DB_ID('tempdb')  
       LEFT OUTER JOIN master.sys.objects AS osr
            ON ts.object_id = osr.object_id AND ts.database_id = 32767  
WHERE  max_worker_time - min_worker_time >= 10 *  total_worker_time / CAST(execution_count AS FLOAT)
             
)
SELECT SQL_TYPE, BASE, CAST(min_worker_time / 1000.0 AS DECIMAL(16,3)) AS TEMPS_MIN_MS,  
       CAST(max_worker_time / 1000.0 AS DECIMAL(16,3)) AS TEMPS_MAX_MS,
       CAST(ECART_MUS / 1000.0 AS DECIMAL(16,3)) AS ECART_MS,
       CAST(ECART_FOIS AS DECIMAL(16,0)) AS ECART_FOIS, CODE                
FROM   T
ORDER BY ECART_FOIS DESC

Dans ces deux requêtes, veuillez remplacer Base1, base2, base3… par le noms de vos bases de production.


--------
Frédéric Brouard, SQLpro - ARCHITECTE DE DONNÉES, http://sqlpro.developpez.com/
Expert bases de données relationnelles et langage SQL. MVP Microsoft SQL Server
www.sqlspot.com : modélisation, conseil, audit, optimisation, tuning, formation
* * * * *  Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence  * * * * *

MVP Microsoft SQL Server

Laisser un commentaire