日期:2014-05-16  浏览次数:20503 次

提高DB2访问的并发性
最近在研究DB2数据库的锁与并发性,在DB2 V8之前,DB2的并发访问没Oracle做的好,这一点是事实,以下我们先看一下Oracle的并发读、写相互影响的机制:
先出现\后出现     读工作负载     写工作负载
  读工作负载        否(不堵塞)       否(不堵塞)
  写工作负载        否(不堵塞)       是( 堵塞 )

而DB2 V8之前的并发读、写相互影响的机制:
先出现\后出现     读工作负载     写工作负载
  读工作负载        否(不堵塞)       可能
  写工作负载        是(堵塞)       是( 堵塞 )

在DB2 V8之前,在游标稳定性(CS)和读稳定性(RS)隔离级别下DB2数据库的并发访问性能不是很好:读访问会影响写访问、写访问会影响读访问、写访问会影响写访问;
为了提高DB2数据库在游标稳定性(CS)和读稳定性(RS)隔离级别下的查询(读)并发性,从DB2 V8以后引入了三个DB2注册表变量:
1、DB2_EVALUNCOMMITTED这个DB2注册表变量:
        当它被启用时,它将修改DB2中只读查询的行为,以减少锁冲突,使之允许在索引扫描(必须是type-2索引)或表访问时推迟锁,直到限定语句的所有谓词都是已知的。
        引入这个新的注册表变量是为了可选地提高一些应用程序的并发性,其实质是允许读扫描推迟或避免行锁,只能获得那些符合某个谓词的行上的锁,而并不是获得被检查的所有行上的锁。直到适合特定查询的一个数据记录成为已知。
        这个注册表变量的作用是判断该SQL谓词所扫描的行是否有锁,如果没有就可以检索到数据。
        这个注册表变量影响DB2在游标稳定性(CS)和读稳定性(RS)隔离级别下的行锁机制。
        当你启用该功能时,DB2可以对未提交的插入(INSERT)或者更新(UPDATE)数据进行谓词判断,如果未提交数据不符合这条语句的谓词判断条件,DB2将不对未提交数据加锁。
        这样就免了因为要对未提交数据加锁而引起的锁等待状态,提高了应用程序访问的并发性,同时DB2在无条件进行表扫描时会忽略删除的行数据(不管是否提交)。
        这里分两种情况来看待:
                第一种情况:对于插入(INSERT)或者更新(UPDATE),如果未提交数据不符合这条语句的谓词判断条件,DB2将不对未提交数据加锁。
                第二种情况:通过上面的实验我们发现在启用DB2_EVALUNCOMMITTED=ON时,对于DELETE操作,DB2在无条件进行表扫描时会忽略删除的行数据(不管是否提交)。
        个人觉得有很大的问题,通过上面的这个测试,一个会话删除一条记录并没有提交,另外一个会话查询的时候已经没有这条记录了,这相当于UR隔离级别。这样显然是不符合业务要求的。与其这样还不如锁住。
        所以启用DB2_EVALUNCOMMITTED=ON时,对于删除操作应该注意多多测试。
        当您的DB2 环境中启用了DB2_EVALUNCOMMITTED行为时,您应该清楚,谓词计算可能发生在未提交的数据上。
        而且,在表扫描访问中,被删除行会被无条件忽略,而对于type-2索引扫描,被删除的键不会被忽略(除非您还设置了DB2_SKIPDELETED注册表变量)。
        如果您要在DB2环境中单独设置DB2_SKIPDELETED注册表变量,DB2将允许在表扫描访问时无条件地忽略被删除行,并忽略type-2索引扫描访问的伪删除索引键。

2、DB2_SKIPDELETED这个DB2注册表变量:
        当它被启用时,将允许使用CS或RS隔离级别的语句在索引扫描期间无条件地跳过被删除的键,而在表访问期间则无条件地跳过被删除的行。
        当DB2_EVALUNCOMMITTED被启用时,被删除的行会被自动跳过,但是除非同时启用了DB2_SKIPDELETED,否则type-2索引中未提交的伪删除键不会被跳过。
        但是这个功能在实际环境中用的时候一定要结合业务逻辑使用,因为这种情况下等同于"脏读",所以一定多测试。

3、DB2_SKIPINSERTED这个DB2注册表变量:
        当它被启用时,DB2将把未提交的INSERT(只适于CS和RS隔离级别)看作它们还没有被插入(如果没有启用该功能,如果未提交的插入数据符合这条语句的谓词判断条件,将会导致锁等待)。
        该特性增加了并发性,同时又不牺牲隔离语义。
        DB2为扫描器实现了这种能力,通过锁属性和锁请求的反馈,使其忽略未提交的插入行,而不是等待。

以上这三个DB2注册表变量都是实力级别的,每次启用/停用这些特性后都需要重启实例才能生效,输出结果如下:
        db2set DB2_EVALUNCOMMITTED=ON(OFF) -i
        db2set DB2_SKIP