提高DB2访问的并发性

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

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

在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_SKIPDELETED=ON(OFF) -i
db2set DB2_SKIPINSERTED=ON(OFF) -i
db2stop force
db2start
----------------------------------------------------------------------------------
到DB2 V9.7版本时增加了"当前已落实"(Currently Committed)的功能:

当前已落实(Currently Committed)工作原理:
从 DB2 V9.7 开始,DB2 通过采用完全锁定避免(full lock avoidance techniques)技术,当能够明确获得数据或者页的"已落实"版本时,允许扫描避免使用行级锁。当无法获知索引或行记录是否已落实时,扫描将改为使用传统的锁定方式。 DB2 通过在行级锁定中增加新的反馈机制,来标识哪些“日志记录”描述了该行的首次修改(从该行的首次修改,就可以获得修改前的数据值,也就是该行的已落实版本),当发生一个锁冲突时锁管理器将使用该反馈机制直接返回这些日志记录编号。一个当前已落实扫描将用使用该反馈结果,用来从日志(日志缓冲区中或者活动日志文件中)访问该行的"当前已落实"版本(也就是首次更新之前的结果值)。未提交的插入行在行级锁中是直接被标识的,允许"当前已落实"扫描直接忽略或跳过该行。

默认情况下,新创建的数据库"当前已落实"处于开启状态,这将允许任何的应用程从DB2 V9.7当前已落实这个新特性中获益(不需要对现有的应用做任何的更改)。
如果你的数据库是从之前的版本升级上来的,那么默认情况下,"当前已落实"设置是处于不启用状态的。你可以通过数据库配置参数cur_commit来启用或不启用"当前已落实"设置。
同时,你还可以通过BIND和PRECOMPILE/PREP命令对其CONCURRENTACCESSRESOLUTION子句指定USE CURRENTLY COMMITTED或WAITFOROUTCOME 来请求命令,对某个独立的应用单独设置"当前已落实",以替代数据库级别的设置。

如何获取或请求"当前已落实":
可以通过配置数据库配置参数 CUR_COMMIT 获取"当前已落实"或者通过 BIND/PRECOMPILE/PREP命令对其CONCURRENTACCESSRESOLUTION子句指定USE CURRENTLY COMMITTED 或 WAIT FOR OUTCOME 来请求"当前已落实"。
一、数据库配置参数 cur_commit:
该数据库配置参数主要是用来控制游标稳定性扫描的行为,默认值为 ON,可选值为:
(1)ON :打开;
对于新创建的数据库,默认值是 ON,在此情况下,当你试图读取一个正在被其他应用程序修改的行时,将直接返回该行的当前已落实版本数据(也就是首次更改之前的值)。
(2)AVAILABLE:可用;
此值表示你的应用需要显式地请求“当前已落实行为”才能得到“当前已落实”结果。
(3)DISABLED:禁用;
如果数据库是从之前的版本升级而来,这个参数将被设置成 DISABLED,这是为了和以前版本的行为保持一致。如果你希望使用当前已落实来控制游标稳定性扫描的行为,需要将这个参数更改成 ON 。
需要注意的是,注册表变量 DB2_EVALUNCOMMITTED、DB2_SKIPDELETED 和 DB2_SKIPINSERTED 在启用 cur_commit 参数后会受到影响。在绑定(BIND)或预编译(PRECOMPILE)时对 CONCURRENTACCESSRESOLUTION 选项指定 USE CURRENTLY COMMITTED 或 WAIT FOR OUTCOME,那么注册表变量DB2_EVALUNCOMMITTED、DB2_SKIPDELETED 和 DB2_SKIPINSERTED 将被忽略。
二、BIND 和 PRECOMPILE/PREP 的命令 CONCURRENTACCESSRESOLUTION 子句BIND 和 PRECOMPILE/PREP 命令的 CONCURRENTACCESSRESOLUTION 子句主要是为了对程序包中的语句指定使用并行访问解析,语法结构如清单 3 所示:
清单 3. BIND 命令 CONCURRENTACCESSRESOLUTION 子句语法结构:
>> - BIND - - filename - - - - - - - - - - - - - - - - - - - - - - - - - - >
> - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - - >
' - CONCURRENTACCESSRESOLUTION - - + - USE CURRENTLY COMMITTED - + - '
' --- WAIT FOR OUTCOME - - --- - '
- - 清单 3 - 2 . PRECOMPILE/PREP 命令 CONCURRENTACCESSRESOLUTION 子句语法结构:
>> - + - PRECOMPILE - + - - filename - - - - - - - - - - - - - - - - - - ->
' - -- PREP - - - '
> - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - >
' - CONCURRENTACCESSRESOLUTION - - + - USE CURRENTLY COMMITTED - + - '
' ---- WAIT FOR OUTCOME - - - - - '

1、USE CURRENTLY COMMITTED:
该选项值表示:当数据处于更新或删除的过程中时,指定数据库管理器对扫描行为使用“当前已落实版本”,当行处于插入的过程中时这个设定将被跳过。当隔离级别处于游标稳定性或者读稳定性隔离级别时(对读稳定性隔离级别这个子句将只跳过未提交的插入操作)这个子句将有效,并且将忽略掉其他设置。
2、WAIT FOR OUTCOME:
该选项值表示:当遇上数据正处于更新的过程中时,指定游标稳定性或更高的隔离级别扫描等待其提交或回滚完成。当行处于插入或删除的过程中时这些行在扫描时将不再被跳过。这个选项值将会造成 DB2_EVALUNCOMMITTED、 DB2_SKIPDELETED 和 DB2_SKIPINSERTED 不再生效。


对于这个配置参数,在必须在所有应用程序都与此数据库断开连接之后,更改才会生效:
db2 update db cfg using cur_commit on
db2 force applications all

下面我们解释几个名词的含义:
(1)隐式“当前已落实”:
是指当数据库上的“当前已落实”设置启用,而请求没有显式的请求“当前已落实”(也就是数据库配置参数 CUR_COMMIT=ON,而且请求没有通过BIND 或 PREP 命令将 CONCURRENTACCESSRESOLUTION 选项设置成 USE CURRENTLY COMMITTED 或 WAIT FOR OUTCOME)。
(2)显式“当前已落实”:
是指程序包中的语句通过 BIND 或 PREP 命令显式的请求“当前已落实”(通过 BIND 或 PREP 命令将 CONCURRENTACCESSRESOLUTION 选项设置成 USE
CURRENTLY COMMITTED)。
(3)“等待运行结果”(Wait For Outcome):
是指程序包中的语句通过 BIND 或 PREP 命令显式的发出“等待运行结果”请求(通过 BIND 或 PREP 命令将 CONCURRENTACCESSRESOLUTION 选项设置成 WAIT FOR OUTCOME)。

以下是“当前已落实”对一些注册表变量的影响:
[color=red]隐式"当前已落实"[/color] 隐式"当前已落实" [color=red]显式"当前已落实"[/color] "等待运行结果"
[color=red]显式"当前已落实"[/color] CS写操作 [color=red]CS写操作[/color] CS读/写操作
[color=red]CS只读操作[/color] RS读/写操作 [color=red]RS读/写操作[/color] RS读/写操作
[color=red]DB2_SKIPINSERTED[/color] 无效 无效 无效 无效
[color=red]DB2_SKIPDELETED[/color] 无效 [color=green]有效[/color] 无效 无效
[color=red]DB2_EVALUNCOMMITTED[/color] 无效 [color=green]有效[/color] 无效 无效



参考资料:[url]http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0906chengy/[/url]

你可能感兴趣的:(数据库)