SQL Server 阻塞、死锁和最大并行度

1.阻塞

阻塞:是指当一个数据库会话中的事务,正在锁定其他会话事务想要读取或修改的资源,造成这些会话发出的请求进入等待的状态。SQL Server 默认会让被阻塞的请求无限期地一直等待,直到原来的事务释放相关的锁,或直到它超时 (根据 SET LOCK_TIMEOUT参数)、进程被杀死、服务器关闭。一般系统中,偶尔有短时间的阻塞是正常且合理的;但若设计不良的程序,就可能导致长时间的阻塞,这样就不必要地锁定了资源,而且阻塞了其他会话欲读取或更新的需求,系统表现为很卡。

项目中平时遇到的大多数是阻塞问题,比如系统页面报超时错误、SSMS中执行一条原本很快的SQL却卡住执行不了或需要执行很久、甚至整个数据库处于瘫痪卡死状态(严重情况)等。

阻塞的原因有很多,这里简单罗列下:

1.并发执行大量表扫描的SQL,由于缺失索引,造成大量阻塞,这种现象非常常见,例如网站首页中某个模块加载的SQL中缺失索引,导致网站首页访问超时。

2.隔离级别的问题,SQL Server默认隔离级别为READ COMMITTED,级别越高,并发性越差,造成阻塞的几率也越高。

3.长时间运行的SQL或者存储过程,由于执行效率较低或内容较多,事务期间会阻塞住其他会话执行


 

2.死锁

死锁:是指多个事务会话互相等待对方释放持有的锁而造成的环路,如果没有外部干预,死锁将无限期持续下去。Sqlserver 中默认产生死锁时,会根据事务开销选择终止并回滚其中某一个事务,让其他事务获取所需的锁完成事务提交。如果系统出现大量死锁,会导致用户使用过程中出现大量死锁报错页面,事务数据无法正常提交,影响系统使用。

死锁发生的现象往往是很明显的,页面会出现报错,如下图

3.阻塞与死锁区别

阻塞现象:系统访问超时、卡慢 
死锁现象:系统访问报错

死锁其实也是由于阻塞造成的,会话之间先是阻塞,然后又因为产生交叉访问,造成环路,最终死锁。死锁的发生其实和阻塞是类似的,只不过阻塞是一种串行的等待,而死锁是交叉环路。

等待方式:默认情况下,当数据库出现阻塞时,如果没有人工干预,那么该会话会一直阻塞下去,直到阻塞该会话的事务结束,或直到LOCK_TIMEOUT设置的超时等待时间(默认为0即无限); 而当出现死锁时,数据库会立即根据事务的回滚开销,来选择终止(回滚)其中一个事务,进而解除死锁,所以死锁会造成操作无效。

4.排查维护

SQLServer 性能排查指南

4.1 阻塞处理

当系统突然发生了超时或卡顿等情况,可以先使用下面的脚本查看数据库阻塞情况,正常情况下没有结果或者出现少量短时间阻塞,问题发生时,通常会出现大量长时间阻塞,可以根据显示的BlockingSession_TSQL进行查看是SQL性能问题还是程序问题,必要时可以选择kill掉阻塞的会话来解决。

 SELECT  R.session_id AS WaitingSessionID ,  
            S.session_id AS BlockingSessionID ,  
            Q1.text AS WaitingSession_TSQL ,  
            Q2.text AS BlockingSession_TSQL ,  
            A.wait_duration_ms as WAIT_DURATION_MS ,
            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  
            INNER JOIN sys.dm_os_waiting_tasks AS A ON A.session_id = C1.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.2 死锁处理

当系统中出现死锁时,可以使用SQl Profile进行死锁监控(具体方法参考SQLServer 性能排查指南),捕捉到死锁后进行分析,看是否是由于SQL缺失索引导致。

5.最大并行度

SQL Server 通过设置最大并行度来限制并行计划执行时所用的处理器数,默认为0,即不限制,由SQL Server自己控制并行。

并行开销阈值:指定SQLServer创建和运行并行查询计划的阈值,仅当运行同一查询的串行计划的估计开销高于在“并行的开销阈值”中设置的值时,SQLServer才创建和运行该查询的并行计划。开销指的是在特定硬件配置中运行串行计划估计需要花费的时间(秒)。

我们的业务系统一般都是为OLTP,理想情况下事务很短,这时候其实就没必要通过并行来提高运行速度,所以对于这类系统来说,可以把最大并行度设为1,也就是不适用并行操作,从而减少不必要的资源等待。

如果是OLAP,由于事务普遍较长,所以并行操作往往能提高速度和资源利用率。

个人观点:对于最大并行度,项目上出现过几次该问题,导致系统访问超时,修改为1也就是关闭最大并行度后,问题解决。对于我们公司的系统来说,大部分事务都很短,不需要并行,小部分较长的事务可以改写SQL来使用并行; 另外也可以调整并行阈值,同时设置并行度为0或是固定值;

SELECT * FROM TEST  WHERE OBJECT_ID =1 OPTION (MAXDOP 8) 

没有最好的方法,只有最适合的方法

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值