查找阻塞语句

此篇扩展随笔事务隔离级别与阻塞中的例子
按照会话1->会话2的顺序执行,会话1(spid=53)开启事务更新数据尚未提交

--会话1开启事务更新数据尚未提交
USE AdventureWorks2008;
GO
BEGIN TRANSACTION;
    -- 修改1
    -- 休假时间减8
    UPDATE HumanResources.Employee
        SET VacationHours = VacationHours - 8
        WHERE BusinessEntityID = 4;

会话2(spid=54)读取会话1中修改的行

--会话2读取会话1中修改的行
USE AdventureWorks2008;
GO
BEGIN TRANSACTION;
    -- 查询1
    -- 这个查询会被会话1阻塞
    SELECT BusinessEntityID, VacationHours
        FROM HumanResources.Employee
        WHERE BusinessEntityID = 4;

查看两个会话的连接信息

select spid,kpid,blocked,waittime,lastwaittype,waitresource,dbid,login_time,last_batch,open_tran,status,loginame
from sys.sysprocesses where spid in(53,54)
select session_id,most_recent_session_id,connect_time,last_read,last_write,client_net_address
from sys.dm_exec_connections where session_id in(53,54)


会话1(spid=53)在2016-11-11 17:09:30建立连接,最后一次读(last_read)是2016-11-11 17:41:45
会话2(spid=54)在2016-11-11 17:28:14建立连接,最后一次读(last_read)是2016-11-11 17:42:27
实际情况是会话1、会话2在分别在2016-11-11 17:09:30、2016-11-11 17:28:14建立连接;会话1在2016-11-11 17:41:45执行更新操作,会话2在2016-11-11 17:42:27执行查询操作,会话1会阻塞会话2。
注意,上图中同一会话sys.sysprocesses的last_batch与sys.dm_exec_connections的last_read看似非常接近,但如果会话2中没有GO关键字,在阻塞的某个点取消执行查询,等上一分钟再次执行会话2的语句,就会出现last_batch是取消执行查询的时间点,last_read是一分钟后的时间。如果会话2使用下面的语句

select top 1 * from AdventureWorks2008.dbo.DatabaseLog
--USE AdventureWorks2008R2;
--GO
--BEGIN TRANSACTION;
    -- 查询1
    -- 这个查询会被会话1阻塞
    SELECT BusinessEntityID, VacationHours
        FROM AdventureWorks2008.HumanResources.Employee
        WHERE BusinessEntityID = 4;

请问会话2能返回DatabaseLog中的一条数据吗?答案是不能。这里不展开讨论,有兴趣的可自行测试。
针对开始的会话2语句,可用下面语句查看阻塞信息

SELECT ec1.session_id                            AS BlockedSessionId
      ,db.name                                   AS DatabaseName
      ,wt.wait_type                              AS WaitType
      ,ec1.last_read                             AS BlockedTime
      ,wt.wait_duration_ms/1000                  AS [WaitDuration(s)]
      ,ec1.client_net_address                    AS BlockedClientAddress
      ,h1.text                                   AS BlockedSQLText
      ,wt.blocking_session_id                    AS BlockingSessionId
      ,h2.text                                   AS BlockingSQLText
      ,sp.program_name                           AS BlockingProgramName
      ,COALESCE(sp.loginame, sp.nt_username)     AS BlockingLoginame
FROM sys.dm_tran_locks  AS tl WITH(NOLOCK)
INNER JOIN sys.databases AS db  WITH(NOLOCK)
  ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt  WITH(NOLOCK)
  ON wt.resource_address = tl.lock_owner_address
INNER JOIN sys.dm_exec_connections  ec1 WITH(NOLOCK)
  ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections  ec2 WITH(NOLOCK)
  ON ec2.session_id = wt.blocking_session_id
LEFT OUTER JOIN master.dbo.sysprocesses AS sp WITH(NOLOCK)
  ON sp.spid = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2


Blocked*代表被阻塞的连接,Blocking*代表阻塞的"源头"。阻塞发生都是一个会话(spid=53)先执行,另一个会话(spid=54)后执行,阻塞发生的时间(BlockedTime)应该理解成后执行的会话的last_read时间。因为会话spid54的连接在被阻塞之前就已经创建(connect_time),并且还有可能执行过其他语句。
完成上面操作后,我们回滚会话1和会话2中的事务。然后按照会话2->会话1的顺序执行
会话2(spid=54)修改隔离级别可重复读,开启事务读取数据

--会话2在可重复读下读取数据
set transaction isolation level repeatable read
go
USE AdventureWorks2008;
GO
BEGIN TRANSACTION;
    -- 查询2
    -- 休假时间为48
    SELECT BusinessEntityID, VacationHours
        FROM HumanResources.Employee
        WHERE BusinessEntityID = 4;

会话1(spid=53)开启事务更新会话2中读取的行

--会话1开启事务更新会话2中读取的行
USE AdventureWorks2008;
GO
BEGIN TRANSACTION;
    -- 修改2
    -- 这个更新会被会话2阻塞
    UPDATE HumanResources.Employee
        SET VacationHours = VacationHours - 8
        WHERE BusinessEntityID = 4;

查看两个会话连接信息

会话1(spid=53)在2016-11-11 17:09:30建立连接,最后一次读(last_read)是2016-11-11 18:05:56
会话2(spid=54)在2016-11-11 17:28:14建立连接,最后一次读(last_read)是2016-11-11 18:04:14
实际情况是会话1、会话2在分别在2016-11-11 17:09:30、2016-11-11 17:28:14建立连接;会话2在2016-11-11 18:04:14在可重复读隔离级别下执行查询操作,会话1在2016-11-11 18:05:56执行更新操作,会话2会阻塞会话1。
此时可用下面语句查看阻塞信息,此语句参考SQL Server 监控统计阻塞脚本信息修改

SELECT ec1.session_id                            AS BlockedSessionId
      ,db.name                                   AS DatabaseName
      ,wt.wait_type                              AS WaitType
      ,ec1.last_read                             AS BlockedTime
      ,wt.wait_duration_ms/1000                  AS [WaitDuration(s)]
      ,ec1.client_net_address                    AS BlockedClientAddress
      ,h1.text                                   AS BlockedSQLText
      ,wt.blocking_session_id                    AS BlockingSessionId
      ,h2.text                                   AS BlockingSQLText
      ,sp.program_name                           AS BlockingProgramName
      ,COALESCE(sp.loginame, sp.nt_username)     AS BlockingLoginame
FROM sys.dm_tran_locks  AS tl WITH(NOLOCK)
INNER JOIN sys.databases AS db  WITH(NOLOCK)
  ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt  WITH(NOLOCK)
  ON wt.resource_address = tl.lock_owner_address
INNER JOIN sys.dm_exec_connections  ec1 WITH(NOLOCK)
  ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections  ec2 WITH(NOLOCK)
  ON ec2.session_id = wt.blocking_session_id
LEFT OUTER JOIN master.dbo.sysprocesses AS sp WITH(NOLOCK)
  ON sp.spid = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2


阻塞的"源头"并没有体现出事务隔离级别,如何获取连接的事务隔离级别。sys.dm_exec_requests中的transaction_isolation_level只对正在运行连接有效,sleeping状态根本无法查询。而DBCC USEROPTIONS要到对应会话上执行才会返回结果,如果是客户端的连接呢?难道只能等用户再次执行语句时才能捕获到其隔离级别?

时间: 2024-12-26 07:21:33

查找阻塞语句的相关文章

解决一阻塞语句CPU直降15%

原本只是部署作业获取数据库中阻塞语句,中午测试汇集阻塞数据,发现某一服务器写入386行,而其他服务器只写入几行.登录对应服务器查看详细信息,发现有四个时间点分别写入100来行记录对于第一行:会话183被会话221阻塞,阻塞时长1887ms,会话221持有18:1:4311755上的U锁,会话183等待18:1:4311755上的U锁.查看BlockedBatch/BlockingBatch列,此处的阻塞与被阻塞对应的存储过程是相同的,只是传递的参数不同.存储过程定义如下 CREATE PROCE

SQL SERVER性能分析--死锁检测数据库阻塞语句

工作中数据库经常出现内存,找了篇文章 参照CSDN,中国风(Roy)一篇死锁文章 阻塞:其中一个事务阻塞,其它事务等待对方释放它们的锁,同时会导致死锁问题. 整理人:中国风(Roy) 参照Roy_88的博客 http://blog.csdn.net/roy_88/archive/2008/07/21/2682044.aspx 日期:2008.07.20 ************************************************************************

快速排查SQL服务器阻塞语句

SELECT*FROM sys.sysprocesses where spid>50 and blocked>0 --可以查看阻塞 SELECT SPID=p.spid, DBName =convert(CHAR(20),d.name), ProgramName =program_name, LoginName =convert(CHAR(20),l.name), HostName =convert(CHAR(20),hostname), Status= p.status, BlockedBy

3.2.5.6 查找英语语句里所有形容词

3.2.5.6 查找英语语句里所有形容词 如果想查找在一段文字里所有出现匹配的字符,需要使用findall()函数,而不是使用search()函数.例如,如果有一个英语作家想把一段英语里所有形容词查找出来,他或她就会使用findall()来实现这个功能. 例子: text = "He was carefully disguised but captured quickly by police." print(text) print(re.findall(r"\w+ly&quo

Verilog HDL中阻塞语句和非阻塞语句的区别

Verilog语言中讲的阻塞赋值与非阻塞赋值,但从字面意思来看,阻塞就是执行的时候在某个地方卡住了,等这个操作执行完在继续执行下面的语句,而非阻塞就是不管执行完没有,我不管执行的结果是什么,反正我继续下面的事情.而Verilog中的阻塞赋值与非阻塞赋值正好也是这个意思,通过执行一个例子,就可以简单地明白了:1.阻塞赋值可以理解为语句的顺序执行,因此语句的执行顺序很重要2.非阻塞赋值可以理解为语句的并行执行,所以语句的执行不考虑顺序3.在assign的结构中,必须使用的是阻塞赋值 下面给出实例来说

查询SQL阻塞语句

SELECT SPID=p.spid, DBName = convert(CHAR(20),d.name), ProgramName = program_name, LoginName = convert(CHAR(20),l.name), HostName = convert(CHAR(20),hostname), Status = p.status, BlockedBy = p.blocked, LoginTime = login_time, QUERY = CAST(TEXT AS VAR

Verilog的非阻塞语句放到顺序块中,综合出来怎样的逻辑电路?

情境: FPGA里面计数器需要复位(计数值置零),与计数器状态有关的行为是状态机控制的,即状态机为CLEAR_TIMER状态时,计数器才完成清零动作. 清零有两个条件:(1)计数器值溢出(达到OVF门限):(2)清零信号有效(1有效).这两个条件是独立的,没有先后关系的约束. 问题是:如何写Verilog语句,才使得这两个触发的优先级相同? 有两个思路: 一个是: [email protected](posedge clk)begin if(!rst_n)begin stat_preload <

Verilog中阻塞(=)与非阻塞语句(&lt;=)

阻塞赋值语句(=)与非阻塞赋值语句(<=)区别叙述如下:       1.在串行语句中,阻塞赋值语句按照排列顺序依次执行:非阻塞赋值语句没有先后之分,并行执行,排在前面语句不影响后面语句(实质是通过每级之间加一个D触发器实现).       2.赋值语句执行时,阻塞的先计算右端表达式的值,然后立刻将值赋给左边变量:非阻塞的也是先计算右端表达式的值,但是要等待延时后再将值赋给左边(同样因为D触发器).文字叙述起来不直观,我们看例子.例:下面代码实现一个寄存器********************

查找Idsql语句 web界面连接数据库

import java.io.IOException;import java.io.PrintWriter;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;