现在的位置: 首页 > 数据库 > 正文

SQLServer发生长时间阻塞的原因有哪些?怎样解决SQLServer阻塞进程

2020年05月19日 数据库 ⁄ 共 2873字 ⁄ 字号 评论关闭

  在SQLServer中,一个阻塞的进程会无限期地保持阻塞,或者直到它超时(根据setlock_timeout)、服务器关闭、进程被杀死、连接完成了更新或者其他发生在原始事务上的操作导致它释放了资源上的锁。下面学步园小编来讲解下SQLServer发生长时间阻塞的原因有哪些?怎样解决SQLServer阻塞进程?

  SQLServer发生长时间阻塞的原因有哪些

  在一个没有索引的表上的过量的行锁会导致SQLServer得到一个锁,从而阻塞其他事务。应用程序打开一个事务,并在事务保持打开的时候要求用户进行反馈或交互。这通常是让最终用户在GUI上输入数据而保持事务打开的时候发生。此时,事务引用的任何资源都会被占据。事务BEGIN后查询的数据可能在事务事务开始前被调用查询不恰当地使用锁定提示。例如,应用程序仅使用很少的行,但却使用一个表锁提示应用程序使用长时间运行的事务,在一个事务中更新了很多行或很多表(把一个大量更新的事务变成多个更新较少的事务有助于改善并发性)。

  怎样解决SQLServer阻塞进程

  找出阻塞的进程后,我们使用sys.dm_exec_sql_text动态管理函数和sys.dm_exec_Connections(DMV)找出正在执行的查询的SQL文本,然后强制结束进程。

  强制结束进程,我们使用kill命令。kill的用法,请参看MSDN:http://msdn.microsoft.com/zh-cn/library/ms173730.aspx

  该命令有三个参数:

  sessionID要终止的进程的会话ID。sessionID是在建立连接时为每个用户连接分配的唯一整数(int)。在连接期间,会话ID值与该连接捆绑在一起。连接结束时,则释放该整数值,并且可以将它重新分配给新的连接。使用KILLsessionID可终止与指定的会话ID关联的常规非分布式事务和分布式事务。UOW标识分布式事务的工作单元(UOW)ID。UOW是可从sys.dm_tran_locks动态管理视图的request_owner_guid列中获取的GUID。也可从错误日志中或通过MSDTC监视器获取UOW。有关监视分布式事务的详细信息,请参阅MSDTC文档。使用KILLUOW可终止孤立的分布式事务。这些事务不与任何真实的会话ID相关联,与虚拟的会话ID='-2'相关联。可使标识孤立事务变得更为简单,其方法是查询sys.dm_tran_locks、sys.dm_exec_sessions或sys.dm_exec_requests动态管理视图中的会话ID列。WITHSTATUSONLY生成由于更早的KILL语句而正在回滚的指定sessionID或UOW的进度报告。KILLWITHSTATUSONLY不终止或回滚sessionID或UOW,该命令只显示当前的回滚进度。

  在第一个查询窗口:

  BEGINTRANUPDATEProduction.ProductInventorySETQuantity=400WHEREProductID=1ANDLocationID=1

  第二个窗口:

  UPDATEProduction.ProductInventorySETQuantity=406WHEREProductID=1ANDLocationID=1

  第三个窗口:

  SELECTblocking_session_id,wait_duration_ms,session_idFROMsys.dm_os_waiting_tasksWHEREblocking_session_idISNOTNULL/*blocking_session_idwait_duration_mssession_id522387654*/

  可以看出是SessionID为52的会话阻塞了SessionID为54的会话。

  那么,52正在干啥坏事呢?在第三个窗口中执行:

  SELECTt.textFROMsys.dm_exec_connectionscCROSSAPPLYsys.dm_exec_sql_text(c.most_recent_sql_handle)tWHEREc.session_id=54/*text(@1int,@2tinyint,@3tinyint)UPDATE[Production].[ProductInventory]set[Quantity]=@1WHERE[ProductID]=@2AND[LocationID]=@3*/

  注意:这并不是第一个查询窗口中的原SQL语句,SQLServer进行了自动参数化计划缓存(预编译)。

  我们强制终止会话。在第三个窗口中执行:

  kill52注意:窗口一的语句和窗口二的语句均终止。

  提示:第三个语句中,使用sys.dm_exec_connections(DMV)返回了SessionID为53的most_recent_sql_handle列。这是SQL文本在内存中的指针。作为sys.dm_exec_sql_text动态管理函数的输入参数使用。从sys.dm_exec_sql_text返回了text列,该列显示了阻塞进程的SQL文本。假如阻塞成串,必须通过blocking_session_id和session_ID列仔细查看每一个阻塞进程,直到发现原始的阻塞进程。

  配置语句等待锁释放的时长

  假如有一个事务或语句被阻塞,意味着它在等待资源上的锁被释放。我们可以事先通过setlock_Timeout来设定需要等待的时间。

  语法如下:SETLOCK_TIMEOUTtime_period

  参数以毫秒为单位。超过时会返回锁定错误。示例:

  在第一个窗口中执行:

  USEAdventureWorksBEGINTRANUPDATEProduction.ProductInventorySETQuantity=400WHEREProductID=1ANDLocationID=1

  在第二个窗口中执行:

  USEAdventureWorksSETLOCK_TIMEOUT1000UPDATEProduction.ProductInventorySETQuantity=406WHEREProductID=1ANDLocationID=1/*1秒后的执行结果Msg1222,Level16,State51,Line3Lockrequesttimeoutperiodexceeded.Thestatementhasbeenterminated.*/

  解析:在这个示例中,我们设置了锁超时时间为1000毫秒,即1秒。这个设置不会影响资源被进程占有的时间,只会影响等待另一个进程释放资源访问的时间。

  以上就是关于“SQLServer发生长时间阻塞的原因有哪些?怎样解决SQLServer阻塞进程”的内容,希望对大家有用。更多资讯请关注学步园。学步园,您学习IT技术的优质平台!

抱歉!评论已关闭.