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