查找慢的Sql语句


本文将带你用最简单的方式监控sql的运行时间。在一个非常繁忙的系统上,一次运行成百上千的 sql,因此找到并微调运行速度较慢的 sql 很重??要。

以下 sql 片段打印前 5 个较慢的 sql 语句。

SELECT TOP 5
      qs.total_elapsed_time / qs.execution_count / 1000000.0 AS average_seconds,
      qs.total_elapsed_time / 1000000.0 AS total_seconds,
      qs.execution_count,
      qs.total_rows,
      qs.last_rows,
      qs.min_rows,
      qs.max_rows,
      SUBSTRING(qt.text,qs.statement_start_offset/2 +1, 
                 (CASE WHEN qs.statement_end_offset = -1 
                       THEN LEN(CONVERT(nvarchar(max), qt.text)) * 2 
                       ELSE qs.statement_end_offset end -
                            qs.statement_start_offset
                 )/2+1
             ) AS individual_query,
      o.name AS object_name,
      DB_NAME(qt.dbid) AS database_name
FROM 
      sys.dm_exec_query_stats qs
      CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
      LEFT OUTER JOIN sys.objects o ON qt.objectid = o.object_id
WHERE 
      qt.dbid = DB_ID('数据库名')
ORDER BY 
      average_seconds DESC;
SELECT  qs.execution_count ,
        SUBSTRING(qt.text, qs.statement_start_offset / 2 + 1,
                  ( CASE WHEN qs.statement_end_offset = -1
                         THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
                         ELSE qs.statement_end_offset
                    END - qs.statement_start_offset ) / 2) AS query_text ,
        o.name AS objectname ,
        dbname = DB_NAME(qt.dbid) ,
        qs.total_rows ,
        qs.last_rows ,
        qs.min_rows ,
        qs.max_rows 
FROM    sys.dm_exec_query_stats AS qs
        CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
        LEFT OUTER JOIN sys.objects o ON qt.objectid = o.object_id
WHERE   qt.dbid = DB_ID('数据库名')
        AND qt.text LIKE '%SELECT%'
ORDER BY qs.execution_count DESC; 
SELECT TOP 20
        total_worker_time / 1000 AS [总消耗CPU 时间(ms)] ,
        execution_count [运行次数] ,
        qs.total_worker_time / qs.execution_count / 1000 AS [平均消耗CPU 时间(ms)] ,
        last_execution_time AS [最后一次执行时间] ,
        max_worker_time / 1000 AS [最大执行时间(ms)] ,
        SUBSTRING(qt.text, qs.statement_start_offset / 2 + 1,
                  ( CASE WHEN qs.statement_end_offset = -1
                         THEN DATALENGTH(qt.text)
                         ELSE qs.statement_end_offset
                    END - qs.statement_start_offset ) / 2 + 1) AS [使用CPU的语法] ,
        qt.text [完整语法] ,
        dbname = DB_NAME(qt.dbid) ,
        OBJECT_NAME(qt.objectid, qt.dbid) ObjectName
FROM    sys.dm_exec_query_stats qs WITH ( NOLOCK )
        CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE   execution_count > 1
ORDER BY total_worker_time DESC;

上面的代码片段使用sys.dm_exec_query_stats视图,它只返回缓存的查询计划。因此,当从缓存中删除计划时,相应的行将从该视图中删除。

上面的代码片段将输出十个字段,individual_queryobject_name,分别database_name代表正在运行的 sql 文本、对象名称和数据库名称。average_secondstotal_seconds,execution_count帮助您跟踪 CPU 成本时间。total_rowslast_rowsmin_rows,max_rows帮助您跟踪查询返回的行数。

qt.dbid = DB_ID('Your DB Name')指定要监视的数据库。如果要对所有数据库进行捕获,则可以删除此预测条件。

概括

  • sys.dm_exec_query_stats 显示当前可用的缓存计划,而不是所有计划。
  • sys.dm_exec_query_stats 很容易跟踪sql的运行时间、执行次数、返回行等……
  • 您可以使用sys.dm_exec_query_stats来完成更全面的功能,例如:自动将慢速 sql 语句写入日志文件。