DB2V9.7当前已落实(CurrentlyCommitted)在游标稳定性隔离级别时减少锁等待以及死锁出现的频率DB2V9.7引入了一系列新特性,使客户可以更轻松地节省IT成本。具体包括压缩增强、pureXML增强、易用性增强、监控增强、工作负载管理增强、安全性提高、性能提高、应用开发提高、SQLPL语言支持、SQL兼容性提高和高可用、备份、日志、弹性、恢复提高等。本文的重点是介绍“当前已落实”新特性,该新特性的显著特点是在游标稳定性隔离级别时可以明显减少锁等待的出现,以及死锁的出现频率。通过使用“当前已落实”的CS隔离级别,可以有效提升高吞吐量事务处理环境下的数据库性能。从DB2V9.7开始,DB2通过采用完全锁定避免技术,当能够明确获得数据或者页的“已落实”版本时,允许扫描避免使用行级锁。当无法获知索引或行记录是否已落实时,扫描将改用使用传统的锁定方式。未提交的插入行在行级锁中是直接被标识的,允许“当前已落实”扫描直接忽略或跳过该行。简介从IBMDB2V9.7开始,DB2引入了一系列新特性,使客户可以更轻松地节省IT成本。具体包括压缩增强(通过对XML数据、临时表、索引、数据复制源表的压缩支持,进一步减少了对存储的需求,提高了I/O的效率,提高了对磁盘数据的快速访问)、pureXML增强(通过对pureXML功能的进一步增强,使得数据仓库中可以部署和分析XML数据;现在XML可以在表分区、MDC表、临时表、用户函数、分区数据库环境中使用)、易用性增强(通过对易用性的增强,减少了总体拥有成本TCO,减少了执行系统管理任务对系统的影响,扩展了以前版本发布的自治特性)、监控增强(可以更灵活、更高粒度的监控DB2环境)、工作负载管理增强(新增调配正在进行的活动的优先级、与Linux工作负载管理WLM集成、对服务类提高缓冲池中I/O优先级控制等,新增了AGGSQLTEMPSPACE、CPUTIME、CPUTIMEINSC、SQLROWSREAD、SQLROWSREADINSC等阈值,改进了基于时间的阈值ACTIVITYTOTALTIME、CONNECTIONIDLETIME的粒度)、安全性提高(可以对敏感数据进行更好的保护)、性能提高(通过在游标稳定性隔离级别下引入“当前已落实”、扫描共享、在表分区上创建分区索引、在表中存储内嵌LOB文件等提高了对数据的访问速度,增加了数据的并发性;DB2优化器通过访问计划重用、Statementconcentrator支持等增强了DB2的性能)、应用开发提高(通过“使用ALTERTABLE重命名列名”等简化了数据库对象的管理,通过引入TRUNCATE语句、创建临时表、公共同义词等很多新的功能提高了SQL编程、存储过程开发得到了简化和提高等)、SQLPL语言支持、SQL兼容性提高(可以从诸如ORACLE应用程序等更容易的迁移到DB2环境中)和高可用、备份、日志、弹性、恢复提高等。本文的重点是介绍“当前已落实”(currentlycommittedsemantics,以后会简称CC)新特性,该新特性的显著特点是在游标稳定性(Cursorstability,以后会简称CS)隔离级别时可以明显减少锁等待的出现,以及死锁的出现频率。在DB2V9.7之前的版本中,当我们使用游标稳定性隔离级别(默认的隔离级别)时,一般只锁定事务声明并打开的游标当前引用的行,也就是说该事务一般只锁定当前行,对当前行以外的记录不做锁定;对其所获取的锁一直有效,直到游标重定位或事务终止为止。如果游标重定位,原来行上的锁就被释放,并获得游标现在引用的行上的锁。如果事务修改了它检索到的任何行,那么在事务终止之前,其他事务不能更新或删除该行,即使游标不再位于被更新或删除的行。需要注意:如果只检索的话,一般只锁定当前行;如果对检索的行还进行了更新或删除的话,则对修改的行也进行了锁定,即便指针移向了其他行,对修改行的锁定还是存在。而对修改行的锁定会阻止其他应用程序读取该行,直到对修改行的锁定解除后(对该修改落实后),其他应用才能读取该行。我们首先来看一下ORACLE在Snapshot隔离级别下读操作与写操作堵塞的情况,具体如表格1所示,当读操作遇上读操作、读操作遇上写操作和写操作遇上读操作都不会发生堵塞,而写操作遇上写操作时则会发生堵塞:表1.ORACLESnapshot隔离级别情况下的的堵塞情况先出现的工作负载\后出现的工作负载读工作负载写工作负载读工作负载否(不堵塞)否(不堵塞)写工作负载否(不堵塞)是(堵塞)下面我们看一下在DB2V9.7之前的版本中使用游标稳定性隔离级别时读操作与写操作堵塞的情况,具体如表格2所示,当读操作遇上读操作时不会发生堵塞;当读操作遇上写操作时可能会发生堵塞(FORREADONLY的读操作不会堵塞写操作,而FORUPDATE的读操作由于其行上有U锁,会堵塞写操作);当写操作遇上读操作时一定会发生堵塞,而当写操作遇上写操作时同样会发生堵塞。表格2.DB2V9.7之前的版本中使用CS隔离级别情况下的堵塞情况先出现的工作负载\后出现的工作负载读工作负载写工作负载读工作负载否(不堵塞)可能写工作负载是(堵塞)是(堵塞)再看一下在DB2V9.7中,启用“当前已落实”的游标稳定性隔离级别时的读操作与写操作堵塞的情况,具体如表格3所示,可以看到比DB2之前的版本有了明显的改进,当读操作遇上读操作、读操作遇上写操作和写操作遇上读操作都不会发生堵塞,只有写操作遇上写操作时才会发生堵塞:表格3.DB2V9.7中启用“当前已落实”的CS隔离级别情况下的堵塞情况先出现的工作负载\后出现的工作负载读工作负载写工作负载读工作负载否(不堵塞)否(不堵塞)写工作负载否(不堵塞)是(堵塞)在DB2V9.7中,在游标稳定性隔离级别下,通过启用“当前已落实”新特性,一个读操作已经不需要再等待该变更落实后再返回值,而是直接返回该行未变更前的值(也就是当前已落实的结果值,忽略任何可能发生的未落实操作)。不过需要注意的是在可更新游标中存在例外的情况:如果某行基于它自己之前的内容被更新过,当前已落实结果无法立即返回。在游标稳定性隔离级别使用行级锁的情况(没有启用“当前已落实”)下,可能会出现锁定超时和死锁,特别是那些没有为防止这些问题进行特殊设计的应用程序。某些高吞吐量数据库应用程序不能容忍事物处理过程中的锁等待,某些应用不能容忍处理未提交的数据,但仍然需要不堵塞读操作事务。通过在CS隔离级别下启用“当前已落实”,可以有效提高高吞吐量事务处理环境下的数据库性能。在这些环境中,过多的锁等待是不能容忍的,通过启用“当前已落实”的CS隔离级别,可以有效的减少timeout和deadlocks。在“当前已落实”启用的情况下,只有落实的数据才会被返回,就像之前的例子,现在读操作不需要再等待更新操作释放行级锁了,读操作将直接返回“当前已落实”版本的数据(也就是首次写操作之前的值)。由于“当前已落实”是DB2V9.7的新特性,很多客户不知道该如何使用,本文将重点介绍DB2V9.7关于“当前已落实”新特性以及相关的概念,并结合实际的例子帮助大家理解和提高。当前已落实(CurrentlyCommitted)工作原理从DB2V9.7开始,DB2通过采用完全锁定避免(fulllockavoidancetechniques)技术,当能够明确获得数据或者页的“已落实”版本时,允许扫描避免使用行级锁。当无法获知索引或行记录是否已落实时,扫描将改为使用传统的锁定方式。DB2通过在行级锁定中增加新的反馈机制,来标识哪些“日志记录”描述了该行的首次修改(从该行的首次修改,就可以获得修改前的数据值,也就是该行的已落实版本),当发生一个锁冲突时锁管理器将使用该反馈机制直接返回这些日志记录编号。一个当前已落实扫描将用使用该反馈结果,用来从日志(日志缓冲区中或者活动日志文件中)访问该行的“当前已落实”版本(也就是首次更新之前的结果值)。未提交的插入行在行级锁中是直接被标识的,允许“当前已落实”扫描直接忽略或跳过该行。具体如图1所示,emp表有5条记录,其中第二行和第四行插入操作已经完成,描述该插入操作的日志记录已经存储在使用TSM归档的带库中,具体如图1中右下方红色部分所示;第三行正处于更新状态(还没落实),记录该行的日志记录处于磁盘中的活动日志文件中,该日志记录描述了第三行的首次更改情况,具体如图1右边中间黄色部分所示;第五行正处于插入状态(还没落实),记录该行的日志记录处于磁盘中的活动日志文件中,该日志记录描述了第五行的首次插入情况,具体如图1右边中间黄色部分所示;第一行正处于删除状态(还没落实),记录该行的日志记录处于日志缓冲区中,该日志记录描述了第一行的首次更改情况,具体如图1右边上方绿色部分所示;图1中间的Locklist部分表示锁管理器,在锁管理器中描述了第一行、第三行、第五行处于X锁状态,与这些行对应的日志记录也在该锁管理器中,这就是DB2V9.7对行级锁定新增的反馈机制,来标识哪些“日志记录”描述了该行的首次修改,当发生一个锁冲突时锁管理器将使用该反馈机制直接返回这些日志记录编号,如黑色箭头所示。当其他应用试图读取第一行或第三行时,将会直接从日志缓冲区或日志文件中返回该行的“已落实”版本数据。而对未提交的第五行,扫描将直接忽略或跳过该行。图1.“当前已落实”(CurrentlyCommitted)工作原理“当前已落实”是通过从日志中获取数据的可用性的(即从日志中获取已落实版本的数据),DB2首先会从日志缓冲区中查找数据。当更新事务仍处于活动状态时,已落实版本数据会处于日志缓冲区或磁盘上的活动日志文件中。通过行级锁定中新增的反馈机制,DB2不需要对所有日志文件进行搜索来查找已落实版本数据,而是直接访问合适的日志文件以及文件中的记录(直接I/O访问取代了对所有日志记录的扫描)。当DB2无法在活动日志文件中找到相关记录时,DB2将切换到“当前已落实”不启用的状态,即读操作会等待写操作落实。需要注意的是,启用“当前已落实”特性需要更多的日志表空间,因为记录一个事务内某行的第一次更新需要额外的空间。当检索该行的“当前已落实”映像(也就是第一次修改前的值)时将会用到这些日志数据。根据工作负载的不同,增加的日志数据对需要使用的总日志空间有一个微不足道的或可衡量的影响。当cur_commit数据库配置参数不启用时,将不需要额外的日志空间。如果日志文件所在磁盘存在大量读操作或者磁盘使用率比较高,可以考虑适当增加日志缓冲区参数logbufsz的大小。如果增加logbufsz的大小,还需要考虑增加dbheap数据库配置参数的大小,因为logbufsz所控制的日志缓冲区使用的内存空间是受dbheap参数控制的。默认情况下,新创建的数据库“当前已落实”处于开启状态,这将允许任何的应用程序从这个新特性中获益(不需要对现有的应用做任何的更改)。如果你的数据库是从之前的版本升级上来的,那么默认情况下,“当前已落实”设置是处于不启用状态的。你可以通过数据库配置参数cur_commit来启用或不启用“当前已落实”设置。同时,你还可以通过使用带CONCURRENTACCESSRESOLUTION选项的BIND和PRECOMPILE命令,对某个独立的应用单独设置“当前已落实”,以替代数据库级别的设置。回页首示例在示例数据库SAMPLE中,存在RHETTE.EMPLOYEE和RHETTE.DEPARTMENT两张表,我们分别打开两个DB2CLP窗口,分别称为窗口1和窗口2,在窗口1中连上示例数据库SAMPLE,更新表RHETTE.EMPLOYEE,并试图读取表RHETTE.DEPARTMENT,在窗口2中连上示例数据库SAMPLE,更新表RHETTE.DEPARTMENT,并试图读取表RHETTE.EMPLOYEE,如果不启用“当前已落实”,将会产生一个死锁,并使其中一个应用程序失败,具体如清单1所示:清单1.不启用CC情况下读操作与写操作堵塞示例--窗口1C:\db2connecttosample数