您的位置:首页 > 其它

浅谈Sybase封锁原理和解决方法

2017-03-16 22:34 453 查看
第一部分 锁的有关概念一、锁的类型
ASE有三种封锁类型:排它锁(exclusive lock),简称X锁);共享锁(share lock,简称S锁);更新锁(update lock,简称U锁)。这三种锁的相容矩阵表如下:



  ×:表示不兼容。∨:表示兼容。ASE是自动决定加锁类型的。一般来说,读(select)操作使用S锁,写(update,insert和delete)操作使用X锁。U锁是建立在页级上的,它在一个更新操作开始时获 5a8 ,当要修改这些页时,U锁会升级为X锁。

  二、锁的粒度
  ASE支持三种锁粒度:表锁(Table Lock)、页锁(Allpage Lock—锁数据页和索引页, Datapage Lock—只锁数据页)和行锁(Datarow Lock—只锁数据行)。通常行锁比页锁、表锁的限制更少(或更小)。行锁只对某一数据行锁定,页锁对本页的所有行进行锁定,而表锁则锁定整个表。为了减小用户间的数据争用和改进并发性,ASE试图尽可能地使用行锁。当ASE决定一个语句将访问整个表或表的大多数页时,它用表锁来提供更有效的锁定。锁定策略直接受查询方案约束,如果update或delete语句没有可用的索引,它就执行表扫描或请求一个表锁定。如果update或delete语句使用了索引,它就通过请求页锁来开始,如果影响到大多数行,它就要请求表锁。一旦一个语句积累的页锁超过锁提升阈值,ASE就设法给该对象分配一个表锁。如果成功了,页锁就不再必要了,因此被释放。表锁也在页层提供避免锁冲突的方法。对于有些命令ASE自动使用表锁。  三、死锁(DEADLOCK)
  简单地说,有 5a8 个用户进程,每个进程都在一个单独的页或表上有一个锁。而且每个进程都想在对方进程的页或表上请求不相容锁时就会发生“死锁”。在这种情况下,第一个进程在等待另一进程释放锁,但另一进程要等到第一个进程的对象释放时才会释放自己的锁。

  ASE检查是否死锁,并终止事务中CPU时间积累最小的用户(即最后进入的用户)。ASE回滚该用户的事务,并用消息号1205通知有此死锁行为的应用程序,然后允许其他用户进程继续进行。

  在多用户情形下,每个用户的应用程序都应检查每个修改数据的事务是否有1205号消息,以此确定是否有可能死锁。消息号1205表示该用户的事务因死锁而终止并被回滚。应用程序必须重新开始这个事务处理。
第二部分 查找死锁原因

  死锁的发生对系统的性能和吞吐量都有重要影响,经检测发现,管理信息系统的死锁主要是因为两个或多个线程(登录)抢占同 5cc 表数据资源。引起长时间抢占同一资源不是因为我们需要处理的事务太复杂,时间太长,而往往是因为我们在前端应用程序对数据库作操作时忘了提交。 既然管理信息系统长时间死锁的原因是由于我们忘了提交或者是提交不当,那么我们就可以通过修改程序防止出现死锁。定位死锁出错处主要经过以下三步:
  ① 在死锁出现时,用sp_who,sp_lock获得进程与锁的活动情况。
  ② 结合库表sysobjects和相应的操作员信息表查出被锁的库表与锁住别人的操作员。
  ③ 根据锁定的库表与操作员的岗位,可以估计出程序大约出错处。询问操作员在死锁时执行的具体操作即可完全定位出错处。最后查找程序并修改之。

  下面举几个命令应用的实例:
  实例1、用sp_who获取关于被阻碍进程的信息系统过程,sp_who给出系统进程的报告。如果用户的命令正被另一进程保持的锁阻碍,则如图显示:


  (说明:status列显示“lock sleep”。blk列显示保持该锁或这些锁的进程 16a0 识,即被谁锁定了。loginame列显示登录操作员。结合相应的操作员信息表,便可知道操作员是谁。)
  实例2、用sp_lock2浏览锁,要得到关于当前sql server上保持的锁的报告,可用系统过程sp_lock2 [spid1[,spid2]],spid1,spid2是表master..dbo..sysprocesses中的sql server进程id号,用sp_who可以得到锁定与被锁定的spid号,执行该进程后屏幕显示:


(说明:locktype列显示加锁的类型和封锁的粒度,有些锁的后缀还带有blk表明锁的状态。前缀表明锁的类型:Sh—共享锁,Ex—排它锁或更新锁,中间表明锁死在表上(table或intent)还是在页上(page)。 后缀“blk”表明该进程正在障碍另一个需要请求锁的进程。一旦正在障碍的进程一结束,其他进程就向前移动。“demand”后缀表明当前共享锁一释放, 该进程就申请互斥锁。table_name列显示表表名。)
第三部分 ASE关于锁的系统调优
  一、 调整死锁检测间隔
  ① 通过配置参数“print deadlock information”的设置,在ASE的日志中显示死锁发生的情形。
  ② 如果应用很少发生死锁现象,则可以使用参数deadlock checking period来指定进行死锁检查之前进程的等待时间,这样可以延迟死锁检查而降低开销。
  ③ deadlock checking period 的取值范围是0-2147483缺省值是500,即一进程至少等待500ms后,ASE才准备检查死锁。

  二、死锁预防
  ① 为尽可能避免死锁的出现在所有的事务中都按同一顺序来访问各个表。
尽可能利用存储过程来完成一个事务,以能够保证对各表的访问次序都是一致的。除非有“可重复读”的必要性,否则不要使用holdlock选项。
  ② 事务应缩小且应尽快提交。
  ③ 避免人工输入操作出现在事务中或是同时对该表施加holdlock。
  ④ 避免并发地执行许多像insert,update,delete这类数据修改语句。

  三、数据库锁的配置原则
  ① 锁的数量不要太小,如果锁不够,可通过命令 sp_configure “number of locks”,NUM 进行修改。
  ② 如果需要节省空间,减少维护量,使用所有页锁机制。
  ③ 如果需要加快速度,空间足够,使用数据页锁机制。
  ④ 当通过监测发现锁竞争超过15%时,首先修改加锁最重的表的锁机制,然后再把数据页锁设置为数据行锁。如果发现螺旋锁多,则为该表建立单独的命名缓存并对命名缓存进行分区。
这里举两个有用的实例,可帮助读者获取一些系统参数,用于分析是否需要更改参数配置。
实例1:执行sp_sysmon “00:05:00” 系统采样(报告在5分钟内关于数据缓冲区统计信息,可确定是否I/O开销太大等)
DBCC execution completed。 If DBCC printed error messages, contact a user with
System Administrator (SA) role。
Sybase Adaptive Server Enterprise System Performance Report
===============================================================================
Server Version: Adaptive Server Enterprise/11。9。2。6/1290/P/EBF 10487 ESD
Server Name: Server is Unnamed
Run Date: Dec 27, 2005
Statistics Cleared at: 10:46:59
Statistics Sampled at: 10:51:59
Sample Interval: 00:05:00
(以下缺省,如想查看详细信息,请执行sp_sysmon “00:05:00”)
实例2:执行sp_object_stats “00:05:00”,10,db1(此命令是将5分钟之内竞争激烈的头10个表列出来)
Lock statistics for the top 10 (or less) most contended objects:
Object Name: db1..table1 (dbid=7, objid=555305188, lockscheme=Datarows):-
Row Locks SH_ROW UP_ROW EX_ROW
---------- ---------- ---------- ----------
Grants: 969 0 50
Waits: 3 0 0
Deadlocks: 0 0 0
Wait-time: 6790 ms 0 ms 0 ms
Contention: 0。31% 0。00% 0。00%
Object Name: db1..table3 (dbid=7, objid=1927834080, lockscheme=Allpages):-
Page Locks SH_PAGE UP_PAGE EX_PAGE
Grants: 273760 5880 324
Waits: 16 0 0
Deadlocks: 0 0 0
Wait-time: 684 ms 0 ms 0 ms
Contention: 0。01% 0。00% 0。00%
(以下缺省,如想查看详细信息,请执行sp_object_stats“00:05:00”,10,db1)
从中可看出table3事全页锁,table1是数据行锁,表的竞争都在可接受的范围内,没有需要调整的配置。

  四、数据库锁的提升机制

  ㈠、提升锁时几个命令
  ① ASE中对所有的表都予置了隐含的全页面加锁机制,可用命令
sp_configure “lock scheme”,[allpages|datapages|datarows] 查看锁的类型。当数据库从原先版本的服务器中转储出来重新加载时,所有的表都被定义为全页面加锁的表。
  ② 当建立一个新表时,可以不使用这个 1b68 缺省值,而采用如下的句法格式:
create table <tablename>…lock[allpages|datapages|datarows]
  ③ 为了在使用的一个表中改变加锁类型,可以采用如下的句法格式:
alter table <tablename> lock[allpages|datapages|datarows]
  ㈡、提升锁时需注意几个问题
  锁提升是同类型的提升,Share Page Lock à Share Table Lock,锁提升的前提条件是在该表上不能有其他类型的锁,比如表A上有共享页锁,当共享页锁的数目达到参数“ page lock promotion HWM”的值并且表A上没有其他的锁时,会提升到表级共享锁。在一个现存的表中改变加锁方式,将引起下列三种行动后果发生:
  首先,如果一张表从全页加锁转变为仅对数据加锁,或者从仅对数据加锁转变为全页加锁,在这两种类型之间就要对表进行选择以允许进行存贮格式改变。如果这是一个分区表,就要同时假定必要的并行级别和工作线程已经配置好的情况下,才能执行。其次,对表中的群聚性索引必须重新创建。因为我们要保证数据,所以如果从全页加锁方式转换为只对数据加锁时,这种重新创建可以通过“with sorted_data”来完成。然而,当从仅对数据加锁机制转换为全页加锁方式时,就要进行并行的索引创建操作。(请注意:如果这是一个分区表时,那么并行等级和工作线程的数目必须加以配置才能允许进行这种改变,否则这种迁移将会失败)。最后,非群聚性的索引将被重建。
  由于这些活动同潜在的工作量有关,从全页加锁机制改变为仅对数据加锁或从仅对数据加锁改变为全页加锁机制都可能是耗费时间的活动。为了标注这一点,有以下一些选择:如果可能的话,应该配置使用并行方式。这至少对执行非群聚性索引的哈斯(杂凑,即hashed)创建方法是必须的,但是如果可能的话,采用分区表和分区扫描将使系统得到更大的改进。在选择进入和创建群聚性的索引之后,该任务将被设置检查点(checkpointed)。所以如果有充分的硬件资源,通过允许在任何一个时间点上,检查点任务可以具有多于10个(系统缺省值)的异步I/O请求,利用dbcc进行调谐将能够带来有益的效果。(“maxwritedes”,number) 进一步作为降低使用检查点成本的一种方法,在相关的高速缓冲池(cache pool)、大数据量的I/O操作中,采用对高淘汰程度进行标记的方法,并允许清洁程序(好象家庭主妇一样)保持特别活跃的状态,将为那些检查点需要从高速缓冲池中,刷新较“脏”的页面的而增加的I/O操作次数,并因此花费了在检查点上的时间都能够大大减少作出贡献。如果预先进行了配置,则可以对并行的选择进入可以使用预先分配的盘区。所以,通过将sp_configure “number of pre-allocated extent”设置为16也将对系统性能有明显的积极的效果。

  五、定位出错处
  根据sp_who与sp_lock2命令的结果,结合sysobjects和相应的操作员的信息表。得到操作员及其在死锁时所操作的库表,便大约可以知道应用程序的出错处,再执行dbcc traceon(3604)以进一步认证。最后查找程序并修正之。 有一段时间,笔者维护的数据库频繁出现死锁,查看数据库也没有什么大的操作,cpu利用率也在合理范围内,是什么引起数据库频繁死锁呢,笔者用了以下几步命令,找到了原因:
  ① select * from master syslogshold 执行后发现有一个进程超过了24小时未释放(记下进程的spid号),但这个进程执行了什么命令不能判断。(syslogshold表记录最老的仍活动的事务, 要查询每一数据库在应用中有最老的活动的事务及其开始时间。)
  ② dbcc traceon(3604) 打开数据库的开关,设置输出到屏幕。
  ③ dbcc sqltext(进程号) 这时我们会看到引起阻塞,不能释放的sql语句。
通过以上三步,笔者当时看到引起阻塞不能释放的sql语句只是普通的select语句,但是对同一张表反复提取数据,在对源程序研究后发现在select语句执行后,没有提交事务的语句(即commit),而该程序被广泛使用,造成进程阻塞不断增加,最终导致互锁。找到问题根源后,及时对程序调优,死锁现象在未发生。由此也可看出,在没有进行大的操作时,当进程定义user_transtion 的进程超过60分钟,就应该检查应用程序,调整不合理的程序或业务流程。
第四部分 总结
  据我个人多年对数据库的使用经验,我觉得对于并行性较高的应用要充分考虑使用行级锁,这样对于提高并发性能至关重要!当然,事务都存在利弊两方面,使用行级锁,也会带来一些相应的弊端,比如使用的锁越多,占用的内存也越多,在使用行级锁的表上频繁的进行数据删除、插入操作久而久之会造成数据库碎片的大量生成,数据库性能会下降,且影响业务。所以在使用行锁、页锁或表锁时要根据系统硬件和使用情况作出合理的综合判断,使数据库性能达到最优。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  update insert share