欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SQL SERVER 查看近期死锁

程序员文章站 2022-05-03 11:45:08
在项目运行的过程中,死锁不可能完全避免,但要尽可能减少死锁的出现, 产生死锁的原因主要是: 1,系统资源不足。 2,进程运行推进的顺序不合适。 3,资源分配不当等。 产生死锁的四个必要条件:- 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资 ......

在项目运行的过程中,死锁不可能完全避免,但要尽可能减少死锁的出现,

产生死锁的原因主要是:
1,系统资源不足。
2,进程运行推进的顺序不合适。
3,资源分配不当等。

产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
- 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求时,该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
- 不可剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺。
- 循环等待条件: 系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

 

排查死锁是有哪个sql导致的,死锁产生后即消失,很难让用户重现死锁问题,虽然可以从日志中分析死锁,但非常繁琐,可以利用下面的sql server 扩展事件,查询历史死锁,查询原因:

/****************************************************************
* 检查近期死锁;定位到具体的对象。方便排查问题;
********************************************************************/

declare @sessionname sysname 

select @sessionname = 'system_health'


if object_id('tempdb..#events') is not null begin
    drop table #events
end

declare @target_file nvarchar(1000)
    , @target_dir nvarchar(1000)
    , @target_file_wildcard nvarchar(1000)

select @target_file = cast(t.target_data as xml).value('eventfiletarget[1]/file[1]/@name', 'nvarchar(256)')
from sys.dm_xe_session_targets t
    inner join sys.dm_xe_sessions s on s.address = t.event_session_address
where s.name = @sessionname
    and t.target_name = 'event_file'

select @target_dir = left(@target_file, len(@target_file) - charindex('\', reverse(@target_file))) 

select @target_file_wildcard = @target_dir + '\'  + @sessionname + '_*.xel'

--keep this as a separate table because it's called twice in the next query.  you don't want this running twice.
select deadlockgraph = cast(event_data as xml)
    , deadlockid = row_number() over(order by file_name, file_offset)
into #events
from sys.fn_xe_file_target_read_file(@target_file_wildcard, null, null, null) as f
where event_data like '<event name="xml_deadlock_report%'

;with victims as
(
    select victimid = deadlock.victims.value('@id', 'varchar(50)')
        , e.deadlockid 
    from #events e
        cross apply e.deadlockgraph.nodes('/event/data/value/deadlock/victim-list/victimprocess') as deadlock(victims)
)
, deadlockobjects as
(
    select distinct e.deadlockid
        , objectname = deadlock.resources.value('@objectname', 'nvarchar(256)')
    from #events e
        cross apply e.deadlockgraph.nodes('/event/data/value/deadlock/resource-list/*') as deadlock(resources)
)
select *
from
(
    select e.deadlockid
        , transactiontime = deadlock.process.value('@lasttranstarted', 'datetime')
        , deadlockgraph
        , deadlockobjects = substring((select (', ' + o.objectname)
                            from deadlockobjects o
                            where o.deadlockid = e.deadlockid
                            order by o.objectname
                            for xml path ('')
                            ), 3, 4000)
        , victim = case when v.victimid is not null 
                            then 1 
                        else 0 
                        end
        , spid = deadlock.process.value('@spid', 'int')
        , procedurename = deadlock.process.value('executionstack[1]/frame[1]/@procname[1]', 'varchar(200)')
        , lockmode = deadlock.process.value('@lockmode', 'char(1)')
        , code = deadlock.process.value('executionstack[1]/frame[1]', 'varchar(1000)')
        , clientapp = case left(deadlock.process.value('@clientapp', 'varchar(100)'), 29)
                        when 'sqlagent - tsql jobstep (job '
                            then 'sqlagent job: ' + (select name from msdb..sysjobs sj where substring(deadlock.process.value('@clientapp', 'varchar(100)'),32,32)=(substring(sys.fn_varbintohexstr(sj.job_id),3,100))) + ' - ' + substring(deadlock.process.value('@clientapp', 'varchar(100)'), 67, len(deadlock.process.value('@clientapp', 'varchar(100)'))-67)
                        else deadlock.process.value('@clientapp', 'varchar(100)')
                        end 
        , hostname = deadlock.process.value('@hostname', 'varchar(20)')
        , loginname = deadlock.process.value('@loginname', 'varchar(20)')
        , inputbuffer = deadlock.process.value('inputbuf[1]', 'varchar(1000)')
    from #events e
        cross apply e.deadlockgraph.nodes('/event/data/value/deadlock/process-list/process') as deadlock(process)
        left join victims v on v.deadlockid = e.deadlockid and v.victimid = deadlock.process.value('@id', 'varchar(50)')
) x
order by deadlockid desc

 

利用此脚本排查历史死锁很方便。