DB2 UDB 一般通过一组兼容性规则来控制实用程序的并发操作。如果两个实用程序不需要同时以不可兼容的模式访问相同的 DB2 UDB 对象,就将它们视为是“兼容的”。当一个实用程序作业开始时,DB2 UDB 就检查系统,查看当前是否有其他任何实用程序正处理同一 DB2 UDB 对象。如果该对象当前未被另一实用程序访问,或者如果另一执行实用程序是可兼容的,该实用程序才可以继续。
数据库设计考虑
取得高度并发性应该是指导 DB2 UDB 数据库初始设计的目标之一。在创建各个表的同时,可能要考虑许多影响并发性的功能。您可以在实现创建之后再添加某些功能(例如通过更改 DB2 UDB 对象),但另一些功能则无法添加,或者至少需要大量重复操作和/或打乱当前实现。因此,最好是一开始就考虑这些问题。
分区
我极力建议您将较大的表创建为分区表。一个分区表空间只包含单个分区表。要基于分区索引的键范围将该表分成多个分区。每个分区都是作为单独的数据集(dataset)来创建的,并且可以作为单独的实体由 DB2 UDB 加以处理。
对于大量的批处理操作(INSERT、UPDATE、DELETE),您可以将大型作业划分成较小的作业,利用该分区表结构。许多这些较小的作业可以并发运行(对不同的分区进行),以便减少整个批处理操作的占用时间,从而使另一应用程序进程可以更早地访问该表。
分区表以类似的方式使实用程序作业只作用于所选择的分区,从而允许其他作业或应用程序进程并发访问表中的其他分区。在许多情况下,DB2 UDB 实用程序本身就具有利用分区表的能力,而在其他情况下,它只为用户提供了设计其工作负载的选项,以便支持 DB2 UDB 数据的更高并发性级别。
锁升级
DB2 UDB 使用升级技术来平衡锁定性能开销的并发性需求。当一个应用程序进程持有单个表或表空间上的大量页面锁、行锁或 LOB 锁时,DB2 UDB 就获取该资源上的表或表空间锁,然后释放该资源上以前的页面锁、行锁或 LOB 锁。该过程称作 锁升级。
如果一个使用分区锁定(带有 LOCKPART YES 的 CREATE 或 ALTER)的表上发生锁升级,那么,就只升级当前被锁定的分区,未锁定的分区仍旧未锁定。一旦表空间中发生了锁升级,那么就要用表空间锁来锁定随后访问的未锁定分区。
在执行应用程序时,DB2 UDB 首先使用页面锁或行锁,并且只要该进程访问相对较少的页面或行,还会继续这样做。当该应用程序访问许多页面或行时,DB2 UDB 将变为使用表锁、表空间锁或分区锁。调用锁升级的准确时间是由 LOCKSIZE 和 LOCKMAX.的值决定的。
LOCKSIZE
LOCKSIZE 是 CREATE/ALTER TABLESPACE 语句的选项,在应用程序进程访问表空间中的表时,控制 DB2 UDB 获取的何种类型的锁(即,它决定该锁的“大小”,这有时也称作锁粒度)。该选项的可以是 LOB、TABLESPACE、TABLE、PAGE、ROW 和 ANY。
CREATE TABLESPACE 语句的 LOCKSIZE 参数默认为 ANY。LOCKSIZE ANY 允许 DB2 UDB 选择锁大小。DB2 UDB 通常将 LOCKSIZE PAGE 用于非 LOB 的表,而将 LOCKSIZE TABLESPACE 用于 LOB 表。
我建议在创建表空间时使用该默认值,除非您有理由进行其他选择。如果您选择修改 LOCKSIZE,那么就要根据使用该表空间的应用程序的性能监控结果和并发性特点来做决定。
使用何种大小的锁
在 DB2 V4 中才开始可以使用行级锁。之前,数据页是最小的锁定单元。I/T 行业中的许多人都假定行锁是并发性问题的灵丹妙药,但实际上,它并不能解决所有的并发性问题。在经历许多锁等待、死锁和超时的环境中,它也许提供了较大的改进。但在其他情形下,DB2 UDB 可能在获取更多锁上消耗资源,同时无法成比例地提高并发性。
因为 IRLM 获取、维护和释放行锁所需的处理与页面锁需要的大致相同,所以关于指定锁大小的决定其实就是在较高的锁定开销与并发性的潜在提高之间进行权衡。