sys.dm_exec_requests中statement_start_offset与statement_end_offset

文章目录

  • 1.缘起
  • 2.根因
  • 3.示例
  • 4.附录

1.缘起

mssql中查早阻塞与及其相关联的sql时,遇到如下内容,故记录一下,

substring(dest_blocked.text,der.statement_start_offset/2+1,(case when der.statement_end_offset=-1 then  DATALENGTH(der.statement_end_offset)
	 else der.statement_end_offset end-der.statement_start_offset)/2+1) as blocked_statement

2.根因

statement_start_offset与statement_end_offset主要用于定位sql的起始与结束位置,但是为何要/2+1,从网路上查询得知:

It's because data returned from sys.dm_exec_sql_text function is in Unicode. 
1 character takes 2 bytes. The SUBSTRING works on character data types (not on bytes). 
So we need to divide the number of bytes by 2 + 1 to have location of the first character in SQL Query that is inside text.

主要是因为sys.dm_exec_sql_text返回的offset是unicode,也就是说返回的是bytes数,1个字符要占用2个bytes,而substring使用character为单位取值,故需要除以2

3.示例

看一下示例:
主要用于返回substring取值的sql与不使用substring取值的完整sql
substring取值的sql

select 'a' as A_query,der.session_id,der.statement_start_offset,der.statement_end_offset, substring(dest.text,der.statement_start_offset/2+1,(case when der.statement_end_offset= -1 then datalength(dest.text)
else der.statement_end_offset end - der.statement_start_offset)/2+1) as statement from sys.dm_exec_requests der
cross apply sys.dm_exec_sql_text(der.sql_handle) dest
union
select 'b' as b_query,der.session_id,der.statement_start_offset,der.statement_end_offset, dest.text as statement from sys.dm_exec_requests der
cross apply sys.dm_exec_sql_text(der.sql_handle) dest
order by session_id

返回如下:
在这里插入图片描述
注意上图中的A_query字段:
a 代表使用substring取值的sql
b 代表不使用substring取值的完整sql

如下,是返回的完整sql:
substring取值的sql(sql_1)

EXECUTE [cmCriticalManufacturingODSLink]..[dbo].sp_executesql @sqlcommand, N'@sqlrowcnt int OUTPUT', @sqlrowcnt=@sqlrowcnt output

不使用substring取值的完整sql(sql_2)

(@sqlcommand nvarchar(max),@sqlrowcnt As int OUTPUT)EXECUTE [cmCriticalManufacturingODSLink]..[dbo].sp_executesql @sqlcommand, N'@sqlrowcnt int OUTPUT', @sqlrowcnt=@sqlrowcnt output

由于statement_start_offset返回是104个bytes,换算成字符就是52个字符
比对上面sql_1与sql_2,可以看到sql_1刚好从第53个字符开始截取,这也就是要+1的原因

4.附录

标题1中的完整sql:

select dtl.resource_type,
case when dtl.resource_type in ('database','file','metadata') then resource_type
     when dtl.resource_type in ('object') then object_name(dtl.resource_associated_entity_id,dtl.resource_database_id) 
	 when dtl.resource_type in ('key','page','rid') then (select object_name(object_id,dtl.resource_database_id) from sys.partitions where hobt_id=dtl.resource_associated_entity_id)
	 else 'unidentifer' end as parent_object,
	 dtl.request_mode,
	 dtl.request_status,
	 dowt.wait_duration_ms,
	 dowt.wait_type,
	 dowt.session_id as blocked_session_id,
	 des_blocked.login_name as blocked_user,
	 substring(dest_blocked.text,der.statement_start_offset/2+1,(case when der.statement_end_offset=-1 then  DATALENGTH(der.statement_end_offset)
	 else der.statement_end_offset end-der.statement_start_offset)/2+1) as blocked_statement,
	 dowt.blocking_session_id,
	 der.blocking_session_id,
	 des_blocking.login_name,
	 dest_blocking.text,
	 dowt.resource_description
	 from sys.dm_tran_locks dtl 
join sys.dm_os_waiting_tasks dowt on dtl.lock_owner_address=dowt.resource_address
join sys.dm_exec_requests der on dowt.session_id=der.session_id
join sys.dm_exec_sessions des_blocked on dowt.session_id=des_blocked.session_id
join sys.dm_exec_sessions des_blocking on dowt.blocking_session_id=des_blocking.session_id
join sys.dm_exec_connections dec on des_blocking.session_id=dec.most_recent_session_id
cross apply sys.dm_exec_sql_text( dec.most_recent_sql_handle) dest_blocking
cross apply sys.dm_exec_sql_text( der.sql_handle) as dest_blocked
where dtl.resource_database_id=db_id() and dtl.resource_type not in ('database','file') 

你可能感兴趣的:(MS,SQL,Server,数据库)