SQL SERVER 查询性能优化——分析事务与锁(五)
上接SQL SERVER 查询性能优化——分析事务与锁(四)
(四)未检测到的分布式死锁
某应用程序持有数据库资源,开启事务之后又与用户交互,而在与用户的交互过程中出现了错误,导致数据库资源迟迟不能释放。SQL SERVER 2005/2008 动态管理视图sys.dm_exec_requests提供相关信息,该SESSION_ID的status字段值为“sleeping”,wait_type为“NULL”值。如果是SQL 2005则可以通过Microsoft SQL Server Management Studio管理工具中的“活动监视器--》进程信息”视图,该进程的“开启事务字段”显示非“0”值。如下图。
在SQL 2005(2008)中执行代码,即SQL SERVER 查询性能优化——分析事务与锁(二)中的“例一”,也就是下面的代码,得到如下图。
select spid 进程,STATUS 状态, 登录帐号=SUBSTRING(SUSER_SNAME(sid),1,30) ,用户机器名称=SUBSTRING(hostname,1,12) ,是否被锁住=convert(char(3),blocked) ,数据库名称=SUBSTRING(db_name(dbid),1,20),cmd 命令,waittype as 等待类型 ,last_batch 最后批处理时间,open_tran 未提交事务的数量 from master.sys.sysprocesses --列出锁住别人(在别的进程中blocked字段中出现的值)但自己未被锁住(blocked=0) Where spid in (select blocked from master.sys.sysprocesses) and blocked=0
由于应用程序持有事务,而且应用程序出错之后,没对事务的相应处理,也没有需要等待的资源,但持有事务,与前一种(三)情况类似,但通过SQL PROFILER工具进行跟踪,却无法发现任何错误事件。
建议解决方式
应用程序所造成的分布式死锁,很难加以跟踪分析,需要程序开发人员自行记录该应用程序的行为,比较多用户情况下,在进行哪些工作之后,系统就迟滞无法正常执行下去。这需要程序开发人员保持良好的开发习惯:事务越晚开启越好,使用资源越少越好,一旦开启了事务迟早关闭,事务执行过程中不要与用户有任何交互,要输入的参数或内容应该在开启事务之前就应该输入完毕,对相关数据的各种校验也要在开启事务之前进行校验,事务应该只是在往数据库中插入更新数据时开启,插入更新完毕之后,就立即关闭。
(五)锁定数据粒度太低或太高
用户设置不当的锁定粒度时,如果设置事务一律使用Row lock或table lock均可能产生问题,或是当系统资源使用过度,也很容易产生被锁定的情形。
建议解决方式
可以通过SQL PROFILER 观察“TextData”字段所呈现的SQL语句,观察该应用程序是否设置了锁定提示,若想要暂时停止锁定提示造成的影响,可以通过以下语句
Dbcc traceon(8755)
或以SQL SERVER 激活参数-T 8755 来停止锁定提示功能,若有改善,可以重新考虑从应用程序从新移除锁定提示的可能性。
(六)Compile Blocking
此现象是由于编译存储过程导致被锁定,在master.sys.sysprocesses视图中或sp_lock存储过程中观察到的等待资源字段中的内容是“COMPILE”,或者使用SQL PROFILER 录制过程中出现大量的“SP:REComplie”事件。由于重新编译需要耗费CPU资源,所以,此种锁定是在一长串的被锁定连接中,单一锁定者锁定时间不长,但整个链接各点都有一点耗时,所以在链接尾端的被锁定者需要等待较长时间。同时会出现CPU的使用率比较高。
当存储过程中使用了缓存数据表,而该缓存数据表还需要设置结构,如需要要设置主键或者利用缓存数据表开打开游标,则每次调用该存储过程进,都会要求重新编译。或这个存储过程是当应用程序执行时,常常会被调用的热门存储过程,就会出现Compile Blocking的状况出现。
但存储过程第一次使用时,也会需要编译,所以不要一看到是在等待编译,就识以为是COMPILE Blocking现象。
建议解决方式
使用sp_executesql执行语句,即使用sp_executesql执行SQL语句,SQL语句不会编译为存储过程执行计划的一部分,因此在执行该类语句时,SQL SERVER 会自由的使用高速缓存中的现有语句计划,或者在执行阶段建立新的执行计划,不管任何一种情况,调用存储过程的计划都不会受影响,也不必进行重新编译。
EXECUTE语句也有相同的效果,但不建议你使用。因为使用EXECUTE没有使用SP_EXECUTESQL语句的效率高,因为前者不允许查询参数化。
三、基本原则:
1. 事务不可以跨批处理,语句越短越好,事务期间不要与用户进行交互
2. 小心处理逾时放弃,或者执行错误等情况。
3. 正确建立索引。可以参考本人前面的相关文章。
(如SQL Server 查询性能优化——创建索引原则(一)
SQL Server 查询性能优化——覆盖索引(一)等系列文章)
4. 数据表最好有聚集索引,而且聚集索引的键值不要太大,因为所有的非聚集索引存储的都是聚集索引的键值。不要使用经常需要进行更新的字段做为聚集索引的键值,因为聚集索引一旦进行了变更,则所有的非聚集索引也要跟着进行变更,导致大量的锁定。索引建少了,影响查询效率,建多了,浪费维护的资源与降低新增、修改、删除的效率,所以建好索引之后,要小心观察SQL SERVER 使用索引的情况,将多余的索引删除,对于数据密度大,或者查询条件鉴别率太低的字段不要建立索引。
5. 尽量不要激活Implicit Transaction,以免它长时间的持有事务。
6. 尽量降低事务隔离级别
7. 进行压力测试以了解当大用户量时,交互将造成何种程度的锁定问题。
四、 防止与处理死锁
1.尽量避免或尽快处理锁定,当锁定与被锁定过多时,就可能造成死锁
2.访问资源的顺序要相同。例如连接A先访问资源1,然后访问资源2,而连接B的访问顺序与之相反,则可能发生死锁。不要在开启事务的情况下,调用外部程序,容易造成分布式死锁。
3.让不同的连接使用相同的锁定。或两条连接因为修改相同的资源而互相锁定,如果你的系统对于更新数据的正确性不做强制性要求,可以考虑使用sp_getbindtoken和sp_bindsession两个系统存储过程,让连接共享锁定,则两条连接同时更新数据,也就可能造成数据更新遗失。
例:
use Test go create proc sp_upd_OPINION @OPINIONID varchar(20), @bindToken varchar(255) output as exec sp_getbindtoken @bindToken output update WBK_OPINION set OPINION_VALUE='true' where OPINION_ID=@OPINIONID go create proc sp_upd_OPINION2 @OPINIONID varchar(20), @bindSession varchar(255) output as exec sp_bindsession @bindSession update WBK_OPINION set OPINION_VALUE='False' where OPINION_ID=@OPINIONID go ----在第一个连接中执行 declare @bindToken varchar(255) begin tran exec sp_upd_opinion 'PreEntryIDUse',@bindToken output select * from WBK_OPINION select @@trancount --事务数量为 select @bindToken
----在第二个连接中执行 ---其中@binToken是由第一个连接执行完毕之后,而获取的 begin tran exec sp_upd_opinion2 'PreEntryIDUse',@bindToken select * from WBK_OPINION select @@trancount --事务数量为
---在第三个连接中执行以下语句,由于不在同一个事务之内,所以会被锁定 update WBK_OPINION set OPINION_VALUE='true' where OPINION_ID='PreEntryIDUse' rollback tran ---回滚
1. 你可以根据以上代码,自行编码相应的测试示例,通过Management studio分别使用三条连接来执行更新示例代码,你会发现享有相同TOKEN的两条连接会一同更新,而其获取的@@TRANCOUNT系统变量也是一样的。而不在同一事务中的其他连接则会被锁住。@@TRANCOUNT也与前述的事务无关。
2.提交不同的数据访问路径。如果两条不同连接的SQL语句,因为抢相同索引而导致死锁,可以考虑为不同的访问语句建立不同的索引,通过索引提示强制让两条连接访问各自的索引。或者是两条不同的连接访问相同的数据表,如果引用不同的索引,但各自的访问顺序正彼此交错,形成死锁,则可强制两条连接使用相同的索引,以维护访问先后秩序。
不管如何,采用此类解决方式时,都要考虑额外的性能损耗,因为你通过索引提示强制了索引访问,让查询优化程序不能凭借数据的特性使用最佳的索引。
五、发生死锁后的处理
通过设置SET DEADLOCK_PRIORITY LOW,让不重要的事务自动放弃,并在这些连接执行的业务逻辑中,加上针对死锁的错误处理。
事实上,在非常复杂的高并发量的系统中,要完全预防死锁,或者要知道什么样的用户在特殊的访问次序中会发生死锁,是非常困难的。所以应用程序应该对死锁错误“1205”要有相应的处理,以完成原有的业务逻辑的处理或是善后清除处理。
SQL SERVER 查询性能优化——分析事务与锁(五)的更多相关文章
- SQL Server 查询性能优化 相关文章
来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Ser ...
- Sql Server查询性能优化之走出索引的误区
据了解绝大多数开发人员对于索引的理解都是一知半解,局限于大多数日常工作没有机会.也什么没有必要去关心.了解索引,实在哪天某个查询太慢了找到查询条件建个索引就ok,哪天又有个查询慢了,再建立个索引就是, ...
- SQL Server查询性能优化——堆表、碎片与索引(二)
本文是对 SQL Server查询性能优化——堆表.碎片与索引(一)的一些总结. 第一:先对 SQL Server查询性能优化——堆表.碎片与索引(一)中的例一的SET STATISTICS IO之 ...
- SQL Server查询性能优化——覆盖索引(二)
在SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索引等 ...
- SET STATISTICS IO和SET STATISTICS TIME 在SQL Server查询性能优化中的作用
近段时间以来,一直在探究SQL Server查询性能的问题,当然也漫无目的的查找了很多资料,也从网上的大神们的文章中学到了很多,在这里,向各位大神致敬.正是受大神们无私奉献精神的影响,所以小弟也作为回 ...
- Sql Server查询性能优化之不可小觑的书签查找
小小程序猿SQL Server认知的成长 1.没毕业或工作没多久,只知道有数据库.SQL这么个东东,浑然分不清SQL和Sql Server Oracle.MySql的关系,通常认为SQL就是SQL S ...
- SQL Server查询性能优化——堆表、碎片与索引(一)
SQL Server在堆表中查询数据时,是不知道到底有多少数据行符合你所指定的查找条件,它将根据指定的查询条件把数据表的全部数据都查找 一遍.如果有可采用的索引,SQL Server只需要在索引层级查 ...
- SQL Server 查询性能优化——创建索引原则(一)(转载)
索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...
- SQL Server 查询性能优化——覆盖索引
覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...
随机推荐
- ILSpy搜索功能加强版
1.修改搜索功能,增加如下的额外搜索选项 A.按文本搜索(默认选项) B.按通配符搜索 C.按正则表达式搜索 2.搜索增加如下特性: A.可以按照名字空间检索特定名字空间下的所有类. B.修正了官方版 ...
- 数据库SQL语句中根据当前日期计算其他日期小结
问题描述:我们在写存储过程和函数的时候经常会碰到利用当前日期计算出上周开始日期.结束日期,或者计算上个月的开始日期结束日期等问题.最近写了几个存储过程和函数,其中都涉及到了日期计算问题,在这里简单做一 ...
- 基于Axure的快速原型方法
Axure是一个专业的快速原型设计工具,让负责定义需求和规格.设计功能和界面的专家能够快速创建应用软件或Web网站的线框图.流程图.原型和规格说明文档.作为专业的原型设计工具,它能快速.高效的创建原型 ...
- uva-10305
题意:给出n个任务,任务不是完全独立的,有些任务必须依赖另外一些任务才能执行:m个任务关系. 输出:n个任务的可能执行顺序: 我的解决方法:这就是个赤裸裸的拓扑排序,直接dfs拓扑每一个任务点,然 ...
- [Leetcode]Palindrome Number
Determine whether an integer is a palindrome. Do this without extra space. 这题貌似解法挺多,直接用简单的把数倒置,没有考虑数 ...
- mysql 条件统计
问题描述为使讨论简单易懂,我将问题稍作简化,去掉诸多的背景. 从前有一个皇帝,他有50个妃子,这些妃子很没有天理的给他生了100,000个儿子,于是,皇帝很苦恼,海量的儿子很难管理,而且,他想知道每个 ...
- CodeIgniter2.2.0-在控制器里调用load失败报错的问题
报错如下: hello A PHP Error was encountered Severity: Notice Message: Undefined property: Test::$load Fi ...
- js for 循环中的 变量问题。
今日处理项目中的一个循环,本来就是一个小小的for循环,后来发现该段程序出现了问题,仔细检查代码没有发现其中的错误.无奈只好叫来了老大帮忙.通过在模版中断点调试(该方式只能自己写debugger断点) ...
- 使用SQLIO测试磁盘性能
SQLIO 是一个用于测试存储系统能力的命令行工具,用以获取存储系统相关的性能指标,以判断系统的 I/O 处理能力. 在微软的网站可以下载 SQLIO 的安装包,安装后目录中会出现如下文件: EULA ...
- 软件测试基本理论-IBM模式
软件测试基本理论(1) IBM生产模式 1 参考书目 <IBM-从菜鸟到测试架构师-一个测试工程师的成长日记> 出版社:电子工业出版社 印次:2013年6月 作者:IBM主要工程师 2 ...