关于DB2 数据库并发性(1)

关于 DB2 数据库并发性的探讨(转) 

 

简介: OLTP 数据库通常是高并发的使用模式,具有高的并发性对 OLTP 系统来说至关重要,并发事务实际上取决于资源的使用状况,原则上应尽量减少对资源的锁定时间,减少对资源的锁定范围,从而能够尽量增加并发事务的数量,那么影响并发的因素有哪些呢?这篇系列文章分 2 部分就这个内容进行一些探讨,同时会尽量使用不同的工具(数据库快照、事件监视器、控制中心等)来演示如何监控资源的使用状况,让大家在获得知识的同时,也可以熟悉各种工具的使用。

 

<!-- <div class="ibm-no-print" mce_tmp="1"> <div id="dw-tag-this" class="ibm-no-print"></div> <div id="interestShow" class="ibm-no-print"></div> </div> -->

<script type="text/javascript"></script><!-- Rating_Area_End -->

 

<!-- dW_Summary_Area_END --><!-- CONTENT_BODY -->

<!-- MAIN_COLUMN_BEGIN -->
<!-- Related_Searches_Area_And_Overlays_Begin --><!-- MAIN_COLUMN_CONTAINER_BEGIN -->
<!-- MAIN_COLUMN_CONTENT_BEGIN -->

概述

OLTP 数据库通常是高并发的使用模式,具有高的并发性对 OLTP 系统来说至关重要,并发事务实际上取决于资源的使用状况,原则上应尽量减少对资源的锁定时间,减少对资源的锁定范围,从而能够尽量增加并发事务的数量,那么影响并发的因素有哪些呢?这篇系列文章之一将从 DB2 数据库本身所提供的机制对并发性的影响进行一些探讨,这些机制包括隔离级别、数据库锁参数、实例注册表变量、乐观锁定。

同时本文讨论及实验所基于的环境如下,见图 1:


图 1. DB2 版本
图 1. DB2 版本

设置 DB2 注册表变量 DB2OPTIONS,将自动提交功能关闭,后面的实验默认都基于这个设置。

db2set DB2OPTIONS=+c db2 terminate db2stop db2start
 


隔离级别与并发性

当多个用户访问同一数据库时会发生的现象介绍如下:

在单用户环境中,每个事务都是顺序执行的,而不会遇到与其他事务的冲突。但是,在多用户环境下,多个事务可以(而且常常)同时执行。因此每个事务都有可能与其他正在运行的事务发生冲突。有可能与其他事务发生冲突的事务称为交错的 或并行的 事务,而相互隔离的事务称为串行化 事务,这意味着同时运行它们的结果与一个接一个连续地运行它们的结果没有区别。在多用户环境下,在使用并行事务时,会发生四种现象:

  • 丢失更新:这种情况发生在两个事务读取并尝试更新同一数据时,其中一个更新会丢失。例如:事务 1 和事务 2 读取同一行数据,并都根据所读取的数据计算出该行的新值。如果事务 1 用它的新值更新该行以后,事务 2 又更新了同一行,则事务 1 所执行的更新操作就丢失了。由于设计 DB2 的方法,DB2 不允许发生此类现象。
  • 脏读:当事务读取尚未提交的数据时,就会发生这种情况。例如:事务 1 更改了一行数据,而事务 2 在事务 1 提交更改之前读取了已更改的行。如果事务 1 回滚该更改,则事务 2 就会读取被认为是不曾存在的数据。
  • 不可重复的读:当一个事务两次读取同一行数据,但每次获得不同的数据值时,就会发生这种情况。例如:事务 1 读取了一行数据,而事务 2 在更改或删除该行后提交了更改。当事务 1 尝试再次读取该行时,它会检索到不同的数据值(如果该行已经被更新的话),或发现该行不复存在了(如果该行被删除的话)。
  • 幻像:当最初没有看到某个与搜索条件匹配的数据行,而在稍后的读操作中又看到该行时,就会发生这种情况。例如:事务 1 读取满足某个搜索条件的一组数据行,而事务 2 插入了与事务 1 的搜索条件匹配的新行。如果事务 1 再次执行产生原先行集的查询,就会检索到不同的行集。

维护数据库的一致性和数据完整性,同时又允许多个应用程序同时访问同一数据,这样的特性称为并发性。 DB2 数据库用来尝试强制实施并发性的方法之一是通过使用隔离级别——通过‘事务、隔离级别、锁’机制,它决定在第一个事务访问数据时,如何对其他事务锁定或隔离该事务所使用的数据。 DB2 使用下列隔离级别来强制实施并发性:

  • 可重复的读(Repeatable Read)
  • 读稳定性(Read Stability)
  • 游标稳定性(Cursor Stability)
  • 未提交的读(Uncommitted Read)

可重复的读隔离级别可以防止所有现象,但是会大大降低并发性的程度(可以同时访问同一资源的事务数量)。未提交的读隔离级别提供了最大的并发性,但是后三种现象都可能出现。

DB2 UDB 支持以下隔离级别:可重复读(Repeatable read,RR)、读稳定性(Read stability,RS)、游标稳定性(Cursor stability,CS)、未提交读(Uncommitted read,UR),下面分别讲述:

可重复读(Repeatable read,RR) 确保 工作单元(UOW)期间的任何表行读操作直到 UOW 完成,不会被其他应用程序进程更改。类似地,由另一个应用程序进程更改的任何行直到由该应用程序进程提交,不会被读取。运行在 RR 级别的应用程序进程是完全与并发应用程序进程的效果相隔离的。
 

RR 隔离级别通常会直接对表加 S 锁,所以对并发的影响最大,但有一种情况例外:如果 WHERE 条件字段上建有主键或者 UNIQUE INDEX,并且通过主键或者 UNIQUE INDEX 进行查询,那么数据库将只对表加 IS 锁,结果行加 S 锁——在锁列表足够用,没有发生锁升级的情况下才成立,也就是说,这个时候 RR 级别 =RS 级别,这时不允许其他事务对这些行进行更新或者删除,因为对行的更新或者删除会对相应的行加 X 锁,这和行 S 锁相排斥;其他情况下,会直接对表加 S 锁,这时将不允许其他事务对任何行进行更新或者删除。

下面我们做个实验,验证使用RR隔离级别的查询对表的加锁情况。


表 1. 实验使用的数据模型
表名 表结构 主键/
UNIQUE INDEX
数据规模
TEST_HAVE_PRI 表结构 A 列上建有主键 10 行
TEST_NO_PRI 表结构 无主键和
UNIQUE INDEX
同样的 10 行数据

使用 RR 隔离级别对 TEST_HAVE_PRI 表进行查询,见图 2:


图 2. 执行查询的 session1 窗口
图 2. 执行查询的 session1 窗口

可以看到表 TEST_HAVE_PRI 上加了 IS 锁,行上加了 S 锁,这是通过主键查询时锁的使用情况,见图 3:


图 3. 快照监控窗口
图 3. 快照监控窗口

通过主键字段查询后,被 RR 隔离级别锁定的行,不能够被其他事务更新(UPDATE/DELETE),session2 中的 UPDATE 事务将被锁住,见图 4:


图 4. 执行 UPDATE 事务的 session2 窗口
图 4. 执行 UPDATE 事务的 session2 窗口

通过 DB2 控制中心工具可以查看锁定链条——即谁锁定了谁,打开‘应用程序’窗口,可以看到选中的应用程序状态为‘正在等待锁定’——就是 session2 中的事务的状态,见图 5:


图 5. 控制中心应用程序界面
图 5. 控制中心应用程序界面

点击‘显示锁定链’按钮,进入下一窗口,下图如何解释呢?


图 6. 应用程序锁定链界面
图 6. 应用程序锁定链界面

请点击‘图注’按钮,先了解一下各种图形元素所代表的意思,见图 7:


图 7. 图注界面
图 7. 图注界面

根据图 7 所示,图 6 所表示的意思为:下方框事务正在等待上方框事务释放锁定,也就是 session2 中的事务正在等待 session1 中的事务释放锁定。

更详细的信息,可以通过右键点击方框,选择‘显示锁定详细信息’菜单,见图 8:


图 8. 应用程序锁定链界面
图 8. 应用程序锁定链界面

下图为 session1 中的查询事务获得的锁的详细信息——获得一个表 IS 锁、一个行 S 锁,见图 9:


图 9. 锁定详细信息界面
图 9. 锁定详细信息界面

图 10 为 session2 中的更新事务获得的锁的详细信息,这个事务处于正在等待锁定 状态,获得了一个表 IX 锁,同时想要获得行 X 锁,但是不成功,于是发生了锁等待,与句柄为 901 的代理程序(即运行查询事务的 session1 应用)中的行 S 锁冲突(见图 9),所以只能等待,直到句柄为 901 的代理程序提交或者回滚工作单元,才能真正获得行 X 锁。


图 10. 锁定详细信息界面
图 10. 锁定详细信息界面

表中其他的行可以被其他事务更新,见图 11:


图 11. 执行 UPDATE 操作的 session3 窗口
图 11. 执行 UPDATE 操作的 session3 窗口

使用 RR 隔离级别对 TEST_NO_PRI 表进行查询,让我们看看不通过主键字段查询时锁的使用情况,见图 12:


图 12. 执行查询的 session1 窗口
图 12. 执行查询的 session1 窗口

可以看到表 TEST_NO_PRI 上直接加了 S 锁,其他任何事务不能对此表做任何更新操作 (DELETE/UPDATE/INSERT),见图 13:


图 13. 快照监控窗口
图 13. 快照监控窗口
读稳定性(Read stability,RS)类似于 RR 。但是,运行在 RS 级别的应用程序进程不是完全与并发应用程序进程的效果相隔离的。如果这样的应用程序进程不止一次发出同样的查询,它就会看到更改了的数据或者由其他应用程序进程添加的新的“幻影(phantom)”行。
 

RS 隔离级别会对表加 IS 锁,结果行加 NS 锁,这时不允许其他事务对这些行进行更新(UPDATE/DELETE),但是允许插入任何行,因为对这些行的更新会对相应的行加 X 锁,这和行 NS 锁相排斥——上述说法基于锁列表足够用,没有发生锁升级的情况下才成立。

下面我们做个实验,验证使用RS隔离级别的查询对表的加锁情况:


表 2. 实验使用的数据模型
表名 表结构 索引
TEST 表结构 A 列上建有索引

使用 RS 隔离级别对 TEST 表查询,见图 14:


图 14. 执行查询的 session1 窗口
图 14. 执行查询的 session1 窗口

可以看到表 TEST 上加了 IS 锁,行上加了 NS 锁(存在 32768 个行 NS 锁,这里不一一列举),见图 15:


图 15. 快照监控窗口
关于DB2 数据库并发性(1)

预更新(UPDATE/DELETE)这些行的事务将被锁住,见图 16、图 17:


图 16. 执行 UPDATE 事务的 session2 窗口
图 16. 执行 UPDATE 事务的 session2 窗口

图 17. 执行 DELETE 事务的 session3 窗口
图 17. 执行 DELETE 事务的 session3 窗口

但是可以插入任何行,见图 18:


图 18. 执行 INSERT 事务的 session4 窗口
图 18. 执行 INSERT 事务的 session4 窗口
游标稳定性(Cursor stability,CS)也确保由另一个应用程序进程更改的任何行直到被那个应用程序进程提交,不会被读取。 CS 隔离级别只确保每个可更新游标当前行不被其他应用程序进程更改;在 UOW 期间读过的行可以被其他应用程序进程更改。针对可滚动更新游标,在提交之前,会对所有结果行一直加 U 锁,无论游标滚动到什么地方; CS 隔离级别针对不可更新游标会对表加 IS 锁,如果未在 WHERE 条件字段上创建索引,查询首先会查找锁列表,检查锁列表中是否存在与 IS 锁相排斥的锁,如果存在的话,那么将等待所有持有排斥锁的事务提交,查询才能执行下去;如果 WHERE 条件字段创建了索引,并且使用了索引,那么查询将通过索引得到结果行,然后检查锁列表中是否存在与结果行相排斥的锁,如果存在的话,那么将等待所有持有排斥锁的事务提交,查询才能执行下去 .
 

下面我们做个实验,验证使用CS隔离级别的查询对表的加锁情况:

使用 CS 隔离级别的可更新游标对 TEST_HAVE_PRI 表进行查询,并 FETCH 第 1 行(见图 19),使用的数据模型见表1:


图 19. 执行查询事务的 session1 窗口
图 19. 执行查询事务的 session1 窗口

可以看到表 TEST_HAVA_PRI 上加了 IX 锁,被取的当前行 (a= ’ 1 ’ ) 加了 U 锁,符合条件的其他行暂时不加锁,见图 20:


图 20. 快照监控窗口
图 20. 快照监控窗口

这时其他事务不可以对这行进行更新操作 (UPDATE/DELETE) ——因为行上的 U 锁与 X 锁排斥,但是可以对其他行进行更新(比如对 a= ’ 3 ’这行),见图 21、图 22:


图 21. 执行 UPDATE 事务的 session2 窗口
图 21. 执行 UPDATE 事务的 session2 窗口

图 22. 执行 UPDATE 事务的 session3 窗口
图 22. 执行 UPDATE 事务的 session3 窗口

转到 session1 窗口,继续 FETCH 下一行,这时将释放前一行 (a= ’ 1 ’ ) 上的 U 锁,在当前行上 (a= ’ 2 ’ ) 加 U 锁,见图 23:


图 23. FETCH 下一行
图 23. FETCH 下一行

转到 session2 窗口,可以看到之前被锁住的 UPDATE 语句已经执行成功,见图 24:


图 24. 执行 UPDATE 事务的 session2 窗口
图 24. 执行 UPDATE 事务的 session2 窗口

在 session4 窗口对 a= ’ 2 ’这行进行 UPDATE 操作,可以预见将被锁住,见图 25:


图 25. 执行 UPDATE 事务的 session4 窗口
图 25. 执行 UPDATE 事务的 session4 窗口

转到 session1 窗口,继续 FETCH 下一行,将释放 a= ’ 2 ’这行上的 U 锁(session4 中对 a= ’ 2 ’这行的 UPDATE 事务将成功执行,为什么呢?),将要在 FETCH 的下一行上加 U 锁,发现 session1 中的游标 FETCH 操作被锁住,这又为什么呢?

因为 session1 中的事务释放了 a= ’ 2 ’上的 U 锁,所以 session4 中被锁住的针对 a= ’ 2 ’这条记录进行的 UPDATE 事务能够执行成功,见图 26:


图 26. 执行 UPDATE 事务的 session4 窗口
图 26. 执行 UPDATE 事务的 session4 窗口

为什么 session1 中的事务(FETCH 下一条记录)被锁住呢?是因为这次恰好要 FETCH a= ’ 3 ’这条记录,需要在行上加 U 锁,这与 session3 中的 update 事务对这行所加的 X 锁相排斥,所以 session1 窗口的 FETCH 下一行操作发生了锁等待,直到 session3 中的事务提交或者回滚为止,见图 27:


图 27. 执行 FETCH 操作的 session1 窗口
图 27. 执行 FETCH 操作的 session1 窗口
未提交读(Uncommitted read,UR)对于某些操作,允许在 UOW 期间读过的任何行可以被其他应用程序进程更改,并允许读任何被另一个应用程序进程更改过的行,即使该更改还没有提交。对于其他操作,UR 类似于 CS 。
 

下面我们做个实验,验证使用UR隔离级别的查询是不会获得任何级别锁的:


表 3. 实验使用的数据模型
表名 表结构 索引
TEST_NO_IND 表结构 没有索引

采用 UR 隔离级别查询 TEST_NO_IND 表,同时运行快照,可见,使用 UR 隔离级别查询时,对表 TEST_NO_IND 加了 IN 锁,IN 就是 intent none 意思,就是不加任何锁,见图 28、图 29:


图 28. 执行查询事务的 session1 窗口
图 28. 执行查询事务的 session1 窗口

图 29. 快照监控窗口
图 29. 快照监控窗口

综上所述,离级别对并发性具有最显著的影响,不同隔离级别获得的资源的锁定范围也不同,如果所有事务都能做到不过分贪婪的占有锁资源——锁的范围大、占用时间长,那么事务之间发生锁冲突的可能性将大大降低,事务的并发性也将会很好。那么如何选择正确的隔离级别呢?

使用的隔离级别不仅影响数据库对并发性的支持如何,而且影响并发应用程序的性能。通常,使用的隔离级别越严格,并发性就越小,某些应用程序的性能可能会越低,因为它们要等待资源上的锁被释放。那么,如何决定要使用哪种隔离级别呢?最好的方法是确定哪些现象是不可接受的,然后选择能够防止这些现象发生的隔离级别:

  • 如果正在执行大型查询,而且不希望并发事务所做的修改导致查询的多次运行返回不同的结果,则使用可重复的读隔离级别。
  • 如果希望在应用程序之间获得一定的并发性,还希望限定的行在事务执行期间保持稳定,则使用读稳定性隔离级别。
  • 如果希望获得最大的并发性,同时不希望查询看到未提交的数据,则使用游标稳定性隔离级别。
  • 如果正在只读的表 / 视图 / 数据库上执行查询,或者并不介意查询是否返回未提交的数据,则使用未提交的读隔离级别。 对于统计类报表,不需要得到十分精确的数据,那么最好使用 UR 隔离级别,既可以节省昂贵的锁列表资源,也不会因为锁冲突影响其他事务的执行,同时也不会受到其他事务的影响,顺利的得到统计结果。未提交的读隔离级别通常用于那些访问只读表和视图的事务,以及某些执行 SELECT 语句的事务(只要其他事务的未提交数据对这些语句没有负面效果)。 顾名思义,其他事务对行所做的更改在已经提交之前对于使用未提交的读隔离级别的事务是可见的。但是,此类事务不能看见或访问其他事务所创建的表、视图或索引,直到那些事务被提交为止。类似地,如果其他事务删除了现有的表、视图或索引,那么仅当进行删除操作的事务终止时,使用未提交的读隔离级别的事务才能知道这些对象不再存在了。(一定要注意一点:当运行在未提交的读隔离级别下的事务使用可更新游标时,该事务的行为和在游标稳定性隔离级别下运行一样,并应用游标稳定性隔离级别的约束。)

数据库锁参数与并发性

当应用程序挂起的锁定总数达到可供应用程序使用的最大锁定列表空间量时,锁定将会升级,将影响到应用程序并发性。可用锁定列表空间量由 locklist 和 maxlocks 配置参数确定。

当应用程序达到允许的最大锁定数并且没有其他要升级的锁定时,它将使用锁定列表中为其他应用程序分配的空间。当整个锁定列表已满时,将发生错误。

以下几种原因可能会导致产生过量锁定升级:

  • 锁定列表大小(locklist)对于并行应用程序数目而言可能太小
  • 可供每个应用程序使用的锁定列表百分比(maxlocks)可能太小
  • 一个或多个应用程序使用的锁定数可能过量。

要解决这些问题,可以:

  • 增加 locklist 配置参数值。
  • 增加 maxlocks 配置参数值。
  • 标识具有大量锁定(请参阅locks_held_top监视器元素)的应用程序,或借助以下公式并将该值与maxlocks进行比较以标识在锁定列表中挂起过量锁定的应用程序:
    (((locks held * 36) ⁄ (locklist * 4096)) * 100)
     

这些应用程序还可能因为在锁定列表中使用过量资源而导致其他应用程序中发生锁定升级。这些应用程序可能需要求助于使用表锁定(而不是行锁定),尽管表锁定可能导致lock_waitslock_wait_time增加。

锁参数(LOCKLIST、MAXLOCKS 和 LOCKTIMEOUT)背景知识

这些与锁相关的控制都是数据库配置参数:

  • LOCKLIST表明分配给锁列表的存储容量。每个数据库都有一个锁列表,锁列表包含了并发连接到该数据库的所有应用程序所持有的锁。锁定是数据库管理器用来控制多个应用程序并发访问数据库中数据的机制。行和表都可以被锁定。根据对象是否还持有其它锁,每把锁需要的锁列表字节数不一样:

在 32 位平台上,每个锁需要 48 或 96 字节的锁定列表,这取决于是否对该对象挂起了其他锁:

  •  
    • 对于没有挂起其他锁的对象,挂起一个锁需要96字节
    • 对于已经挂起了锁的对象,记录一个锁需要48字节

64位平台(HP-UX/PA-RISC除外)上,每个锁需要64128字节的锁定列表,这取决于在该对象上是否挂起了其他锁定:

  •  
    • 对于没有挂起其他锁定的对象,挂起一个锁定需要128字节
    • 对于存在一个挂起的锁定的对象,记录一个锁定需要64字节。
  • MAXLOCKS定义了应用程序持有的锁列表的百分比,在数据库管理器执行锁升级之前必须填充该锁列表。当一个应用程序所使用的锁列表百分比达到MAXLOCKS时,数据库管理器会升级这些锁,这意味着用表锁代替行锁,从而减少列表中锁的数量。当任何一个应用程序所持有的锁数量达到整个锁列表大小的这个百分比时,对该应用程序所持有的锁进行锁升级。如果锁列表用完了空间,那么也会发生锁升级。数据库管理器通过查看应用程序的锁列表并查找行锁最多的表,来决定对哪些锁进行升级。如果用一个表锁替换这些行锁,将不再会超出MAXLOCKS值,那么锁升级就会停止。否则,锁升级就会一直进行,直到所持有的锁列表百分比低于MAXLOCKSMAXLOCKS参数乘以MAXAPPLS参数不能小于100

虽然升级过程本身并不用花很多时间,但是锁定整个表(相对于锁定个别行)降低了并发性,而且数据库的整体性能可能会由于对受锁升级影响的表的后续访问而降低。

下面是一些控制锁列表大小的建议:

  •  
    • 经常进行提交以释放锁。
    • 当执行大量更新时,更新之前,在整个事务期间锁定整个表(使用SQL LOCK TABLE语句)。这只使用了一把锁从而防止其它事务妨碍这些更新,但是对于其他用户它的确减少了数据并发性。
    • 使用alter TABLE语句的LOCKSIZE参数控制如何在持久基础上对某个特定表进行锁定。
    • 查看应用程序使用的隔离级别。使用可重复读隔离级别在某些情况下可能会导致自动执行表锁定。当有可能减少所持有共享锁的数量时,可以使用游标稳定性(Cursor Stability)隔离级别。如果没有损害应用程序完整性需求,那么可以使用未提交的读隔离级别而不是游标稳定性隔离级别,以进一步减少锁的数量。

使用下列步骤确定数据库锁列表所需的页数:

  1. 计算锁列表大小的下限:(512 * 32 * MAXAPPLS) / 4096,其中512是每个应用程序平均所含锁数量的估计值,32是对象(已有一把锁)上每把锁所需的字节数。
  2. 计算锁列表大小的上限:(512 * 64 * MAXAPPLS) / 4096,其中64是某个对象上第一把锁所需的字节数。
  3. 对于您的数据,估计可能具有的并发数,并根据您的预计为锁列表选择一个初始值,该值位于您计算出的上限和下限之间。

使用数据库系统监视器调优MAXLOCKS值。

设置MAXLOCKS时,请考虑锁列表的大小(LOCKLIST):

MAXLOCKS = 100 * (512锁/应用程序* 32字节/锁* 2) / (LOCKLIST * 4096字节)

该样本公式允许任何应用程序持有的锁是平均数的两倍。如果只有几个应用程序并发地运行,则可以增大MAXLOCKS,因为在这些条件下锁列表空间中不会有太多争用。

  1. LOCKTIMEOUT指定了应用程序为获取锁所等待的秒数。这有助于应用程序避免全局死锁。
    • 如果将该参数设置成0,那么应用程序将不等待获取锁。在这种情形中,如果请求时没有可用的锁,那么应用程序立刻会接收到-911
    • 如果将该参数设置成-1,那么将关闭锁超时检测。在这种情形中,应用程序将等待获取锁(如果请求时没有可用的锁),一直到被授予了锁或出现死锁为止。

如何更改这些参数

要更改锁参数,请运行以下命令:

db2 -v update db cfg for DB_NAME using LOCKLIST a_number db2 -v update db cfg for DB_NAME using MAXLOCKS b_number db2 -v update db cfg for DB_NAME using LOCKTIMEOUT c_number db2 -v terminate
 

监控步骤

一旦锁列表满了,由于锁升级生成更多的表锁和更少的行锁,因此减少了数据库中共享对象的并发性,从而降低了性能。另外,应用程序间可能会发生更多死锁(因为它们都等待数量有限的表锁),这会导致事务被回滚。当数据库的锁请求达到最大值时,应用程序将接收到值为-912SQLCODE。如果锁升级造成并发性方面的问题,则可能需要增大LOCKLIST参数或MAXLOCKS参数的值。可以使用数据库系统监视器来确定是否发生锁升级,跟踪应用程序(连接)遭遇锁超时的次数,或者数据库检测到的所有已连接应用程序的超时情形。

  1. 首先,运行下面这个命令以打开针对锁的DB2监视器:
db2 -v update monitor switches using lock on db2 -v terminate
 

  1. 然后收集数据库快照:
db2 -v get snapshot for database on DB_NAME
 

  1. 在快照输出中,检查下列各项:
Locks held currently = 0 Lock waits = 0 Time database waited on locks (ms) = 0 Lock list memory in use (Bytes) = 504 Deadlocks detected = 0 Lock escalations = 0 Exclusive lock escalations = 0 Agents currently waiting on locks = 0 Lock Timeouts = 0
 

如果“Lock list memory in use (Bytes) ”超过定义的LOCKLIST大小的50%,那么就增加LOCKLIST数据库配置参数中的4KB页的数量。锁升级、锁超时和死锁将表明系统或应用程序中存在某些潜在问题。锁定问题通常表明应用程序中存在一些相当严重的并发性问题,在增大锁列表参数的值之前应当解决这些问题。

避免死锁

从事务双方的锁定关系上来讲有死锁和活锁 2 种,所谓活锁:举例来说可能会存在事务 A 在等待事务 B 释放所占用的锁资源,但是事务 B 并不等待事务 A 释放所占用的锁资源,所谓死锁:举例来说可能会存在事务 A 在等待事务 B 释放所占用的锁资源,同时事务 B 在等待事务 A 释放所占用的锁资源,也就是说,事务之间互相等待,如果没有合理设置检查死锁的时间间隔 (DLCHKTIME) 参数,可能会导致相关事务双方永远等待下去,DLCHKTIME 参数默认设置为 10000 毫秒——即 10 秒,也就是说每隔 10 秒钟,死锁检测进程会自动检查数据库范围内有无死锁存在,如果发现了死锁存在,那么将随机挑选一个事务并强制终止它,这个事务将被回滚,那么这时另外一个事务将可以顺利执行下去。

总的来说,死锁可能是由下列情况导致的:

  • 数据库发生锁定升级
  • 在系统生成的行锁定已足够的情况下应用程序显式锁定了表
  • 绑定时应用程序使用了不适当的隔离级别
  • 目录表已被锁定以供可重复读
  • 应用程序正以不同的顺序获取相同的锁定,从而导致死锁。

你可能感兴趣的:(数据结构,db2,配置管理,IBM,HP)