阻塞与死锁(二)——各种操作对锁的申请

原文:阻塞与死锁(二)——各种操作对锁的申请

如何监视锁的申请、持有和释放:

在着手分析、处理阻塞、死锁之前,首先要进行“监控”和“信息收集”

1、检查一个连接当前所持有的锁:

可以使用sp_lock来查看所有连接持有的锁的内容。

在2005以后引入的DMV,还能用过sys.dm_tran_locks来查看:

SELECT  request_session_id,
        resource_type ,
        resource_associated_entity_id ,
        request_status ,
        request_mode ,
        resource_description
FROM    sys.dm_tran_locks

也可以组合其他DMV查看更详细的信息:

SELECT  request_session_id,
        resource_type ,
        resource_associated_entity_id ,
        request_status ,
        request_mode ,
        resource_description ,
        p.object_id ,
        OBJECT_NAME(p.object_id) AS OBJECT_NAME ,
        p.*
FROM    sys.dm_tran_locks a
LEFT JOIN sys.partitions p ON a.resource_associated_entity_id = p.hobt_id
WHERE   resource_database_id= DB_ID(‘数据库名‘)
ORDER BY request_session_id,resource_type ,
resource_associated_entity_id

2、监视语句执行过程中SQL Server对锁的申请和释放行为:

由于有很多锁是在语句运行过程中申请和释放的。运行之后锁会消失,所以使用上面方式很难查询。此时使用SQL Server Profiler 来跟踪是比较好的方式:

打开SQL Server Profiler→定义一个跟踪(trace),选取以下的Events(事件):Lock:Accquired,Lock:Released

由于实际过程中申请锁的情况可能会非常复杂,所以建议只在测试环境针对特定语句进行。

一般来说,使用DMV和sp_lock基本上能解决大部分问题。

锁的数量和数据库调优的关系:

一个常见的SELECT动作要申请的锁:

(1)      在连接A中,将事务隔离级别设成【可重复读】(repeatable read)

(2)      在运行查询前开启一个事务

(3)      运行查询语句,但不提交

(4)      在第二个连接里,查询sys.dm_tran_locks中分析查询结束以后连接A还持有的锁。

一个常见的UPDATE动作要申请的锁:

对于一个UPDATE操作,可以理解为先查询再修改。查询的过程先要添加S锁,找到数据后再添加U锁。最后才把U锁升级到X锁。

如果update操作借助了哪个索引,就会在这个索引的键值上有U锁。没有用到的索引不加锁。真正修改的地方会有X锁。对于查询涉及的页面。SQL SERVER加了IU锁。修改发生的页面,加了IX锁。

总结:

(1)          对于每个使用到的索引,SQL Server会对上面的键值加U锁。

(2)          SQL Server只对要修改的记录或键加X锁。

(3)          使用到要修改的列的索引越多,锁的数目也会越多。

(4)          扫描的页面越多,意向锁就越多。扫描过程中,所有扫描到的记录也会加锁。哪怕没有修改。

对此,要在UPDATE过程中降低阻塞的几率,可以做以下方面:

(1)          尽量修改少的记录集。

(2)          减少无谓的索引。

(3)          严格避免表扫描的发生。如果只需要修改表的一小部分,要尽量使用Index Seek,避免全表扫描这种执行计划。

一个常见的DELETE动作要申请的锁:

Delete的时候也和update一样,需要先找出要更改的数据,然后再进行操作。

(1)          DELETE 的过程先找到符合条件的记录,然后做删除。可以理解为先是一个SELECT ,然后一个DELETE。所以,如果有合适的索引,第一步申请的锁会比较少。

(2)          DELETE 不但把数据行本身删除,还要删除所有相关的索引键,所以一张表上的索引数目越多,锁的数目就会越多,越容易发生阻塞。

为了防止阻塞,我们既不能绝对地不建索引,也不能随随便便建很多索引。对于没有用的索引,去掉比较好。

一个常见的INSERT动作要申请的锁:

SQL Server会对新插入的数据本身申请一个X锁。在发生变化的页面申请一个IX锁。由于是新插入的数据,被引用的概率相对小一些,所以发生阻塞的几率也很小。

小结:

数据库开发者和DBA想要影响SQL Server锁的申请和释放行为,以缓解阻塞或死锁的问题,需要考虑以下因素:

1、  事务隔离级别的选定:级别越高,隔离度越高,并发也越低。越高的级别SQL Server会不可避免地申请更多的锁。设计应用时,要和用户谈好,尽量选择默认的隔离级别(READ COMMITTED)。

2、  事务的长短和复杂度:决定了事务在SQL Server内部会持续多长时间,也决定了同时在多少张表和索引上申请和持有锁。避免在一个事务里面做很多事情。

3、  从应用整体并发度考虑,但是事务一次处理的数据量不能过多:如果一个应用的并发要求比较高,就一定要严格控制单个事务处理的数据量。如果有什么事务操作需要访问或修改表内大量数据,最好调整到并发用户比较少的时候运行。

4、  针对语句在表格上设计合适的索引:如果没有合适的索引,在做SELECT /UPDATE/DELETE 的时候,申请多得多的锁。对这种情况,可以通过加索引提高并发性。但是,索引越多,申请的锁数目也会越多。对于设计人员,要确保有足够的索引,防止语句做全表扫描。但也要去掉对语句运行贡献不大的索引,不能随便往表格上加索引。

数据库引擎中基于行版本控制的隔离级别:

在默认设置下,一个读操作会和一个写操作相互阻塞。在未提交读,虽然不会,但是读操作可能读到脏数据。大部分用户是不能接受的。

从2005以后,引入了行版本控制机制。好处是程序并发性比较高但是用户读取数据时虽然不是脏数据但是可能是一个正在被修改马上就要过期的数据值,容易产生逻辑错误。

SQLServer 有两种行版本控制:

使用行版本的已提交隔离(READ_COMMITTED_SNAPSHOT)和直接使用SNAPSHOT事务隔离级别。

l  READ_COMMITTED_SNAPSHOT数据库选项为ON时,READ_COMMITTED事务通过使用行版本控制提供语句级读取一致性。

l  ALLOW_SNAPSHOT_ISOLATION数据库选项为ON时,SNAPSHOT事务通过使用行版本控制提供事务级读取一致性。

可以使用ALTER DATABASE XXX SET READ_COMMITTED_SNAPSHOT/ ON;来开启。

注意:行版本控制并不是消除阻塞和死锁的万灵药。必须考虑两个问题:

1、  最终用户是否接受行版本控制下的运行结果?

2、  SQL Server 是否能支持行版本控制带来的额外负荷?因为行版本放在tempdb,对SQL Server会造成额外的负载。

时间: 2024-08-27 17:27:13

阻塞与死锁(二)——各种操作对锁的申请的相关文章

追踪SQL Server执行delete操作时候锁的申请与释放过程

一直以为很了解sqlserver的加锁过程,在分析一些特殊情况下的死锁之后,尤其是并发单表操作发生的死锁,对于加解锁的过程,有了一些重新的认识,之前的知识还是有一些盲区在里面的.delete加锁与解锁步骤是怎么样的?什么时候对那些对象,加什么类型的琐,加锁与索引的关系是怎么样的,什么时候释放锁?整个过程锁是如何参与整个delete操作过程表的?这里通过一个非常简单的delete语句,来分析一条delete执行过程中加解锁的过程. 测试表创建 用一个最最简单的例子做了跟踪,对锁的申请和释放,有了更

Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇)

目录 Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 1 Internal Locking Methods 2 Metadata Locking 3 External Locking Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 1 Internal Locking Methods 这里介绍Mysql的几种锁,该锁由Mysql自行进行管理,用户不需要处理该锁. Row-Level Locking 对于InnoDB,行锁可以通过SELECT ... FOR UPDAT

锁的种类,阻塞,死锁产生与解决办法。

TM锁的种类: TM锁几种模式的互斥关系: 阻塞 定义:当一个会话保持另一个会话正在请求的资源上的锁定时,就会发生阻塞.被阻塞的会话将一直挂起,直到持有锁的会话放弃锁定的资源为止.4个常见的dml语句会产生阻塞INSERTUPDATEDELETESELECT-FOR UPDATE -------------------------------------------------------------- update 的阻塞     试验: 1.    获得会话sid SQL> select s

第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁

原文:第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦测和处理这类问题. 死锁是当两个或者以上的事务互相阻塞引起的.在这种情况下两个事务会无限期地等待对方释放资源以便操作.下面是死锁的示意图: 本文将使用SQLServer Profiler来跟踪死锁. 准备工作: 为了侦测死锁,我们需要先模拟死锁.本例将使用两个不同的会话创建两个事务. 步骤: 1. 打

第十六章——处理锁、阻塞和死锁(2)——侦测阻塞和阻塞查询

原文:第十六章--处理锁.阻塞和死锁(2)--侦测阻塞和阻塞查询 前言: 如果一个事务正在等待一些给其他事务锁定的资源.这个事务就被成为"被阻塞的事务".反过来,引起阻塞的事务,也就是锁定资源并造成其他事务等待的事务叫做"正在阻塞的事务". 长时间运行事务会阻塞其他事务和查询,使他们等待长时间.在繁重的系统中,很多时候我们会遇到阻塞问题,如果一个事务因为阻塞未完成.会造成一些列的等待链. 本文将介绍如何发现并马上解决这方面的问题. 准备工作: 本例依旧使用SQLSe

第十六章——处理锁、阻塞和死锁(1)——确定长时间运行的事务

原文:第十六章--处理锁.阻塞和死锁(1)--确定长时间运行的事务 前言: 事务是OLTP系统中的主要部分.它管理数据一致性和数据并发问题,当多个资源同时被读取或者修改相同数据时,SQLServer会通过锁定机制来确保数据库中的数据总是处于一个有效状态.在SQLServer中,锁管理器是负责实现这些锁机制.SQLServer对于不同的资源类型提供不同的锁类型,如数据库.文件.对象.表.区.页和键. 当你使用事务时,依然会遇到由事务引起的问题,这些通常是由于锁.阻塞和死锁引起的. 本系列将讲解这三

数据库阻塞和死锁的区别

本文来自:http://blog.sina.com.cn/s/blog_6f33ee7901018nsd.html 数据库阻塞和死锁在程序开发过程经常出现,怎么样避免呢?下面通过Demo简单模拟下,数据库发生阻塞和死锁的现象:一.数据库阻塞:    数据库阻塞的现象:第一个连接占有资源没有释放,而第二个连接需要获取这个资源.如果第一个连接没有提交或者回滚, 第二个连接会一直等待下去,直到第一个连接释放该资源为止.对于阻塞,数据库无法处理,所以对数据库操作要及时地提交或 者回滚.Demo:--创建

阻塞与死锁

1,锁发生在事务中.事务的4个属性是:原子性,一致性,隔离性,持久性.(ACID)1)原子性:对于数据的修改,要么全部执行,要么全部不执行,不存在一部分修改而另一部分未变的情况,即使执行一半发生断电的情况,下次启动时也会读取日志将上次未完的操作执行下去(故对于事务,日志优先写入).2)隔离性:对于数据的修改,同一时间只能由一个事务处理3)一致性:事务完成时,必须使所有数据都保持一致状态.4)持久性:事务完成之后,它对于系统的影响是永久性的. 2,隔离级别:mssql通过对共享锁申请和释放机制的不

阻塞与死锁(一)——基础知识

原文:阻塞与死锁(一)--基础知识 阻塞与死锁是除内存.CPU.IO外另一个影响性能的因素.对OLTP系统尤为严重 一般以下问题是死锁的征兆: 1.  并发用户少的时候,一切正常,但是随着用户数量增多,性能越来越慢. 2.  客户端经常收到以下错误: Error 1222:Lock request time out period exceeded.(已超过锁请求超时时段) Error 1205:Your transaction(process ID #XX) was deadlocked on{