zoukankan      html  css  js  c++  java
  • SQL Server 阻塞排除的 2 方法

    背景知识:

                是什么造成了阻塞?

                从锁的观点来看、可访问对象前一定要对对象加锁不管你是读还是写,如果用户A以经持有对象,说明A以在对象上加锁,如果这时B

                也想访问这个对象、它也要对对象加锁。重点来了如果A用户加的是排它锁,B用户可以做的就是乖乖等A用完再说。B乖乖等这个问题

                就是阻塞,是因为这两把锁不可以共存才造成了阻塞。

    场景再现:

                为在再现场景我们要开三个通向数据的连接。就是说要打开三个managerment studio 或是开三个sqlcmd。我用ssms(SQL Server Managerment Studio)为例

                先为场景做点准备,代码如下。

                use Studio;
                go

                create table TestTable (ID int not null,String nchar(10));
                go

                declare @i as int =1;
                while @i<10
                begin
                insert into TestTable(ID,String) values(@i,REPLICATE(cast(@i as nchar(1)),10));
                set @i = @i +1;
                end;
                go

                select T.ID,T.String from TestTable as T;

                go

                

               连接A运行如下代码:

                                        begin tran
                                        update dbo.TestTable
                                        set String = 'AAA'
                                        where ID=1;
                                        go --可以看到A会一直持有第一行上的排它锁,直到事务被commit 或 rollback!

               连接B运行如下代码:                             

                                        update dbo.TestTable
                                        set String = 'BBB'
                                        where ID=1; 

                                        go -- 因A以在ID=1这一行上有排它锁,所以B只可以乖乖的等,这就造成了阻塞。下图可以看出B等了2分多钟了。

                                        

               C连接用来解除阻塞,运行代码马上就讲。

    方法 1、 从锁入手

                            第一步、看谁在等待资源,以确定谁被阻塞、运行如下代码

                                     select
                                     tra.request_session_id as [SessionID],-- 会话名
                                     DB_NAME(tra.resource_database_id) as [DBName],-- 数据库名
                                     tra.resource_type as [resourceType],-- 资源类型
                                     tra.resource_associated_entity_id as [ResourceID],--资源ID
                                     tra.request_status as [Status]  --状态
                                     from sys.dm_tran_locks as tra
                                     where tra.request_session_id>50;
                                     go

                                     

                                     -- 下图中可以看出有一行是wait 说明它在等别人,释放资源。

                                     所以 54 是在等别人,它等谁呢?从图上可以看出 51 持有54在等待对象的排它锁,说明54在等51。

                          第二步、定位等的是哪个资源:

                                                               运行如下代码

                                                               select OBJECT_NAME(565577053);--565577053来自于图上的倒数第二行。
                                                               go

                         第三步、查看因为什么操作造成阻塞:

                                    到目前为止,sys.dm_tran_locks只能帮我们到这里下,我们需要新的武器

                                    sys.dm_exec_connections

                                    select

                                    con.session_id as [SessionID],

                                    con.connect_time as[ConnectTime],

                                    con.most_recent_sql_handle as [SqlHandle] 

                                    from sys.dm_exec_connections as con

                                    where session_id in (51,54);

                                    go

                                    

                                    most_recent_sql_handle 返回连接最后执行SQL语句的指针,注意它不一定就是移动存造成阻塞的原因,它只是最后执行

                                    的SQL语句。 

                                    要看代码这就要用到我们的第三件武器了 sys.dm_exec_sql_text(  )函数                                                            

                                    select

                                    con.session_id as [SessionID],

                                    sqlt.text

                                    from sys.dm_exec_connections as con cross apply sys.dm_exec_sql_text(con.most_recent_sql_handle) as sqlt

                                    where session_id in (51,54);

                                    go

                                               

                         第四步:

                                  解除阻塞,经过上面的三步阻塞的原因基本上以有所了解了。

                                  我们只要把长期占着资源的连接kill(杀死)掉就行了,本例中,是51号连接长占资源不放,所以要kill它。

                                  kill 51;

                                  go

    方法 2、

             下面我们从任务(task)的角度来看问题、阻塞也就是一个任务在等待另一个任务的执行完成,只要找到它在等谁,再把引起等待的任务kill、当然 

             任务是不可以kill的,但是我们不是可以曲线救国吗?kill掉它的连接啊,对吧。

             第一步:

                     找到引起阻塞的进程ID

                     select
                     task.session_id,
                     task.wait_duration_ms,task.
                     blocking_session_id
                     from sys.dm_os_waiting_tasks as task
                     where task.blocking_session_id is not null;
                     go

                     -- 方法1时我以把阻塞排除,下图是一个新的阻塞,所以session_ID上会不一样。

                     

             第二步:

                      接下来就是用

                      sys.dm_exec_connections, sys.dm_exec_sql_text,kill来排除阻塞了,用法如方法1中所说。

             第三步:

                      kill 52; 

              

  • 相关阅读:
    011 Go语言基础之map
    009 Go语言基础之切片
    计算机组成原理 — GPU 图形处理器
    js 实现各浏览器全屏
    js 实现各浏览器全屏
    IIS-真正解决ASP.NET每一个页面首次访问超级慢的问题
    IIS-真正解决ASP.NET每一个页面首次访问超级慢的问题
    首次启动速度慢的问题记录IIS性能优化
    首次启动速度慢的问题记录IIS性能优化
    C#-执行cmd命令,获取结果
  • 原文地址:https://www.cnblogs.com/JiangLe/p/4004631.html
Copyright © 2011-2022 走看看