• sqlserver 数据库阻塞和死锁


    参考原文:http://blog.csdn.net/ha196200/article/details/44985597

     

    (1) 数据库阻塞: 假设第一个连接T1占有且没有释放资源,第二个连接T2请求同一资源(表tb)时需要等待,若T1没有提交或回滚,T2将持续等待,导致阻塞发生。

    第一个连接:

    begin tran
      update tb set num=2 where id=1

    第二个连接:

    begin tran
      update tb set num=2 where id=1
    commit tran

    (2)  数据库死锁: 第一个连接占有资源没有释放,准备获取第二个连接所占用的资源,而第二个连接占有资源没有释放,准备获取第一个连接所占用的资源。这种互相占有对方需要获取的资源的现象叫做死锁。对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行。

    第一个连接:

    begin 
      update t1 set num=2 where id=1; --先修改t1
      waitfor delay '00:00:20'        --等待20s
      update t2 set num=2 where id=1; --再修改t2
    end

    第二个连接:

    begin 
      update t2 set num=2 where id=1; --先修改t1
      waitfor delay '00:00:20'        --等待20s
      update t1 set num=2 where id=1; --再修改t2
    end

    1. Activity Monitor

             

    2. EXEC sp_who2

    3. 检查阻塞

     

    SELECT  R.session_id AS BlockedSessionID ,  
            S.session_id AS BlockingSessionID ,  
            Q1.text AS BlockedSession_TSQL ,  
            Q2.text AS BlockingSession_TSQL ,  
            C1.most_recent_sql_handle AS BlockedSession_SQLHandle ,  
            C2.most_recent_sql_handle AS BlockingSession_SQLHandle ,  
            S.original_login_name AS BlockingSession_LoginName ,  
            S.program_name AS BlockingSession_ApplicationName ,  
            S.host_name AS BlockingSession_HostName  
    FROM    sys.dm_exec_requests AS R  
            INNER JOIN sys.dm_exec_sessions AS S ON R.blocking_session_id = S.session_id  
            INNER JOIN sys.dm_exec_connections AS C1 ON R.session_id = C1.most_recent_session_id  
            INNER JOIN sys.dm_exec_connections AS C2 ON S.session_id = C2.most_recent_session_id  
            CROSS APPLY sys.dm_exec_sql_text(C1.most_recent_sql_handle) AS Q1  
            CROSS APPLY sys.dm_exec_sql_text(C2.most_recent_sql_handle) AS Q2

     4. 检查死锁

    sys.sysprocesses 系统表是一个很重要的系统视图,主要用来定位与解决Sql Server的阻塞和死锁。如 SPID130的blocked 字段值为158,而SPID158 的 blocked 为0,就可以得出结论:130 被 158 阻塞住了。如果你发现一个连接的 blocked 字段的值等于它自己,那说明这个连接正在做磁盘读写,它要等自己的 I/O 做完。

    select spid, blocked, loginame, last_batch, status, cmd, hostname, program_name
    from sysprocesses
    where blocked <>0 or spid in(select blocked from sysprocesses where blocked<>0) 

      5. 检查死锁

    select * from sys.dm_tran_locks where request_status='WAIT'

     6. 自动监测

    CREATE procedure sp_who_lock   
    as     
    begin     
      declare @spid int     
      declare @blk int     
      declare @count int     
      declare @index int     
      declare @lock tinyint      
      set @lock=0      
      create table #temp_who_lock      
      (      
        id int identity(1,1),      
        spid int,      
        blk int     
      )      
      if @@error<>0 return @@error      
      insert into #temp_who_lock(spid,blk)      
      select 0 ,blocked from (select * from master..sysprocesses where blocked>0)a      
      where not exists(select * from  master..sysprocesses where a.blocked =spid and blocked>0)      
      union select spid,blocked from  master..sysprocesses where blocked>0      
      if @@error<>0 return @@error      
      select @count=count(*),@index=1 from #temp_who_lock      
      if @@error<>0 return @@error      
      if @count=0      
      begin     
        select '没有阻塞和死锁信息'     
        return 0      
      end     
      while @index<=@count      
      begin     
        if exists(select 1 from #temp_who_lock a where id>@index and exists(select 1 from #temp_who_lock where id<=@index and a.blk=spid))      
        begin     
          set @lock=1      
          select @spid=spid,@blk=blk from #temp_who_lock where id=@index     
          select '引起数据库死锁的是: '+ CAST(@spid AS VARCHAR(10)) + '进程号,其执行的SQL语法如下'     
          select  @spid, @blk    
          dbcc inputbuffer(@spid)      
          dbcc inputbuffer(@blk)      
        end     
        set @index=@index+1      
     end     
     if @lock=0       
     begin     
      set @index=1      
      while @index<=@count      
      begin     
        select @spid=spid,@blk=blk from #temp_who_lock where id=@index     
        if @spid=0      
          select '引起阻塞的是:'+cast(@blk as varchar(10))+ '进程号,其执行的SQL语法如下'     
        else      
          select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))+ '' + '进程号SPID:'+ CAST(@blk AS VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下'     
        dbcc inputbuffer(@spid)    
        dbcc inputbuffer(@blk)      
        set @index=@index+1      
     end     
    end     
    drop table #temp_who_lock      
    return 0      
    end  

     查看数据库表修改记录

    SELECT [Transaction ID],Operation,Context,AllocUnitName
    FROM fn_dblog(NULL, NULL) 

     查看数据库字段修改记录

    SELECT 
        表名=CASE WHEN C.column_id=1 THEN O.name ELSE N'' END, 
        表说明=ISNULL(CASE WHEN C.column_id=1 THEN PTB.[value] END,N''), 
        字段序号=C.column_id, 
        字段名=C.name, 
        主键=ISNULL(IDX.PrimaryKey,N''), 
        标识=CASE WHEN C.is_identity=1 THEN N''ELSE N'' END, 
        计算列=CASE WHEN C.is_computed=1 THEN N''ELSE N'' END, 
        类型=T.name, 
        长度=C.max_length, 
        精度=C.precision, 
        小数位数=C.scale, 
        允许空=CASE WHEN C.is_nullable=1 THEN N''ELSE N'' END, 
        默认值=ISNULL(D.definition,N''), 
        字段说明=ISNULL(PFD.[value],N''), 
        索引名=ISNULL(IDX.IndexName,N''), 
        索引排序=ISNULL(IDX.Sort,N''), 
        创建时间=O.Create_Date, 
        修改时间=O.Modify_date 
    FROM sys.columns C 
        INNER JOIN sys.objects O 
            ON C.[object_id]=O.[object_id] 
                AND O.type='U' 
                AND O.is_ms_shipped=0 
        INNER JOIN sys.types T 
            ON C.user_type_id=T.user_type_id 
        LEFT JOIN sys.default_constraints D 
            ON C.[object_id]=D.parent_object_id 
                AND C.column_id=D.parent_column_id 
                AND C.default_object_id=D.[object_id] 
    LEFT JOIN sys.extended_properties PFD 
            ON PFD.class=1 
                AND C.[object_id]=PFD.major_id 
                AND C.column_id=PFD.minor_id 
    --             AND PFD.name='Caption'  -- 字段说明对应的描述名称(一个字段可以添加多个不同name的描述) 
        LEFT JOIN sys.extended_properties PTB 
            ON PTB.class=1 
                AND PTB.minor_id=0 
                AND C.[object_id]=PTB.major_id 
    --             AND PFD.name='Caption'  -- 表说明对应的描述名称(一个表可以添加多个不同name的描述) 
        LEFT JOIN                       -- 索引及主键信息 
        ( 
            SELECT 
                IDXC.[object_id], 
                IDXC.column_id, 
                Sort=CASE INDEXKEY_PROPERTY(IDXC.[object_id],IDXC.index_id,IDXC.index_column_id,'IsDescending') 
                    WHEN 1 THEN 'DESC' WHEN 0 THEN 'ASC' ELSE '' END, 
                PrimaryKey=CASE WHEN IDX.is_primary_key=1 THEN N''ELSE N'' END, 
                IndexName=IDX.Name 
            FROM sys.indexes IDX 
            INNER JOIN sys.index_columns IDXC 
    ON IDX.[object_id]=IDXC.[object_id] 
                    AND IDX.index_id=IDXC.index_id 
            LEFT JOIN sys.key_constraints KC 
                ON IDX.[object_id]=KC.[parent_object_id] 
                    AND IDX.index_id=KC.unique_index_id 
            INNER JOIN  -- 对于一个列包含多个索引的情况,只显示第1个索引信息 
            ( 
                SELECT [object_id], Column_id, index_id=MIN(index_id) 
                FROM sys.index_columns 
                GROUP BY [object_id], Column_id 
            ) IDXCUQ 
                ON IDXC.[object_id]=IDXCUQ.[object_id] 
                    AND IDXC.Column_id=IDXCUQ.Column_id 
                    AND IDXC.index_id=IDXCUQ.index_id 
        ) IDX 
            ON C.[object_id]=IDX.[object_id] 
                AND C.column_id=IDX.column_id 
    --WHERE O.name = 'viewvoutpage'
        -- 如果只查询指定表,加上此条件 
    ORDER BY O.name,C.column_id
  • 相关阅读:
    spring-boot整合shiro作权限认证
    spring boot整合redis,以及设置缓存过期时间
    java使用Http调用第三方接口,输入链接,获取返回值
    [C#]加密解密 MD5、AES
    [转]Linux 基本操作(RM 删除)
    [转]Windows 经验集
    [随手记]笔记+经验集
    [转][C#]Socket 手写服务端
    [转][C#]跳过调试
    [转][C#]抓取网页内容
  • 原文地址:https://www.cnblogs.com/anxiao/p/7700538.html
Copyright © 2020-2023  润新知