Определите инструкции SQL из sys.dm_exec_sql_text

У меня есть сценарий SQL, который я написал несколько дней назад, чтобы найти интенсивные запросы CPU с помощью некоторых DMV/DMFs и .sys таблицы (в основном из sys.dm_exec_query_stats).
Однако, чтобы определить точную инструкцию SQL, которая была выполнена в определенный момент времени, я использую следующее (найдено в BOL и различных блогах) в моей инструкции SELECT:
,SUBSTRING(t.text,s.statement_start_offset/2 +1,
(CASE WHEN s.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
ELSE s.statement_end_offset END -
s.statement_start_offset)/2) AS 'TSQL-Query'

Может кто-то объяснит почему.statement_start_offset » сначала делится на два, а затем добавляется один? А также почему оператор LEN () умножается на два?

Я вижу эти примеры во многих блогах , а также на MSDN, но я не могу найти эти детали.

Я также включил весь мой сценарий ниже для того, чтобы вы получили большую картину.

    SELECT TOP 20   
    COALESCE(DB_NAME(t.dbid),
                DB_NAME(CAST(a.value as int))) AS DBNAME                                
    ,SUBSTRING(t.text,s.statement_start_offset/2 +1,                                    
                 (CASE WHEN s.statement_end_offset = -1 
                       THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2 
                       ELSE s.statement_end_offset END - 
                       s.statement_start_offset)/2)                                     
                        AS 'TSQL-Query' 
     ,s.execution_count AS 'Execution Count'
     ,s.total_worker_time AS 'Total CPU'
     ,s.total_worker_time/s.execution_count AS 'Avg CPU (ms)'     
     ,s.total_physical_reads AS 'Total Physical Reads'
     ,s.total_physical_reads/s.execution_count AS 'Avg Physical Reads'
     ,s.total_logical_reads AS 'Total Logical Reads'
     ,s.total_logical_reads/s.execution_count AS 'Avg Logical Reads'
     ,s.total_logical_writes AS 'Total Logical Writes'
     ,s.total_logical_writes/s.execution_count AS 'Avg Logical Writes'
     ,s.total_elapsed_time AS 'Total Duration (ms)'
     ,s.total_elapsed_time/s.execution_count AS 'Avg Duration/execution (ms)'
     ,p.query_plan AS 'ExecutionPlan'
     ,(SELECT sqlserver_start_time FROM sys.dm_os_sys_info) as 'Last Reboot'
     ,GETDATE() AS 'TimeStamp'
FROM sys.dm_exec_query_stats AS s                                                       
CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) AS t                                     
CROSS APPLY sys.dm_exec_query_plan(s.plan_handle) AS p                                  
OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) AS a                                   
 WHERE attribute = 'dbid' 
ORDER BY s.total_worker_time DESC 

1 ответ

  1. Это потому, что данные, возвращаемые sys.dm_exec_sql_textфункцией, находятся в Юникоде. 1 символ занимает 2 байта. SUBSTRINGРаботает на символьных типах данных (не на байтах). Таким образом, нам нужно разделить количество байтов на 2 + 1, чтобы иметь расположение первого символа в SQL-запросе, который находится внутри text.