如何监视锁的申请、持有和释放:
在着手分析、处理阻塞、死锁之前,首先要进行“监控”和“信息收集”
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会造成额外的负载。
分享到:
相关推荐
死锁避免——银行家算法 实验报告,完整代码和演示过程
死锁避免——银行家算法的模拟实现 java源代码 java源代码 java源代码 java源代码 java源代码
死锁流程图 复习画流程图一目了然 操作系统——死锁流程图
有关银行家算法的实现,它是用来解决操作系统中的死锁问题的有效方法!
操作系统处理机调度与死锁PPT课件 操作系统处理机调度与死锁PPT课件 操作系统处理机调度与死锁PPT课件 操作系统处理机调度与死锁PPT课件 操作系统处理机调度与死锁PPT课件 操作系统处理机调度与死锁PPT课件 操作系统...
操作系统 第三章处理机调度与死锁思维导图
操作系统 死锁 课件下载 操作系统 死锁 课件下载 了解:死锁的检测与恢复 理解:死锁的必要条件、死锁的预防 掌握:死锁的避免——银行家算法
上海大学操作系统实验二(死锁)
操作系统课程中关于调度与死锁部分的PPT
从进程同步的概念可以知道,当并发进程需要竞争使用资源或需要相互协作向前推进时,如果... 死锁是所有操作系统都面临着的潜在问题,操作系统除了需要预防死锁、避免死锁外,还需要能够检测死锁,并从死锁中进行恢复。
操作系统课件——05死锁与饥饿_922004864.ppt
SQLSERVER阻塞与死锁ppt课件.ppt
2015 Oracle 技术嘉年华(OTN)分会场11何登成 - 管中窥豹——MySQL(InnoDB)死锁分析之道
SQL死锁-阻塞一般情况下死锁不是一步到位的,它必须满足特定的条件,然后形成资源的循环依赖才会产生死锁,死锁之前一定会出现阻塞,
3.1 并发进程 3.2 临界区管理 3.3 信号量与PV操作 3.4 管程 3.5 进程通信 3.6 死锁
3处理机调度与死锁3处理机调度与死锁3处理机调度与死锁3处理机调度与死锁
模拟死锁检测算法的流程与代码 docx文档 死锁检测算法:当任一进程Pj申请一个已被其他进程占用的资源ri时,进行死锁检测。检测算法通过反复查找进程等待表和资源分配表,来确定进程Pj对资源ri的请求是否导致形成环路...
两种存储过程检查死锁sp_who_ock
操作系统同步与死锁课件。并发进程、进程的交往:竞争和协作。临界区管理