文章目录
- 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') 
                


















