Prayer

在一般中寻求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

INSERT 锁 在DB2中提高INSERT性能的技巧

Posted on 2010-04-23 10:51 Prayer 阅读(2337) 评论(0)  编辑 收藏 引用 所属分类: DB2

为了尽可能好地进行页清除:

* 将 CHNGPGS_THRESH 数据库配置参数的值从缺省的 60 减少到 5 这么低。这个参数决定缓冲池中脏页的阈值百分比,当脏页达到这个百分比时,就会启动页清除。

* 尝试启用注册表变量 DB2_USE_ALTERNATE_PAGE_CLEANING(在 DB2 V8 FixPak 4 中最新提供)。通过将这个变量设置成 ON,可以为页清除提供一种比缺省方法(基于 CHNGPGS_THRESH 和 LSN 间隙触发器)更积极的方法。我没有评测过其效果。请参阅 FixPak 4 Release Notes 以了解这方面的信息。

* 确保 NUM_IOCLEANERS 数据库配置参数的值至少等于数据库中物理存储设备的数量。

 

至于 I/O 本身,当需要建立索引时,可以通过使用尽可能大的缓冲池来将 I/O 活动减至最少。如果不存在索引,则使用较大的缓冲池帮助不大,而只是推迟了 I/O。也就是说,它允许所有新页暂时安放在缓冲池中,但是最终仍需要将这些页写到磁盘上。

当发生将页写到磁盘的 I/O 时,通过一些常规的 I/O 调优步骤可以加快这一过程,例如:

* 将表空间分布在多个容器(这些容器映射到不同磁盘)。
* 尽可能使用最快的硬件和存储管理配置,这包括磁盘和通道速度、写缓存以及并行写等因素。
* 避免 RAID5(除非是与像 Shark 这样有效的存储设备一起使用)。

 

5. 锁

缺省情况下,每一个插入的行之上都有一个 X 锁,这个锁是在该行创建时就开始有的,一直到 insert 被提交。有两个跟 insert 和锁相关的性能问题:

* 为获得和释放锁而产生的 CPU 开销。
* 可能由于锁冲突而导致的并发问题。

 

对于经过良好优化的批量插入,由获得每一行之上的一个 X 锁以及后来释放该锁引起的 CPU 开销是比较可观的。对于每个新行之上的锁,惟一可以替代的是表锁(DB2 中没有页锁)。当使用表锁时,耗时减少了 3%。有 3 种情况可以导致表锁的使用,在讨论表锁的缺点之前,我们先用一点时间看看这 3 种情况:

* 运行 ALTER TABLE LOCKSIZE TABLE。这将导致 DB2 为随后使用该表的所有 SQL 语句使用一个表锁,直到 locksize 参数改回到 ROW。

* 运行 LOCK TABLE IN EXCLUSIVE MODE。这将导致表上立即上了一个 X 锁。注意,在下一次提交(或回滚)的时候,这个表将被释放,因此,如果您要运行一个测试,测试中每 N 行提交一次,那么就需要在每次提交之后重复执行 LOCK TABLE。

* 使用缺省锁,但是让 LOCKLIST 和 MAXLOCKS 数据库配置参数的值比较小。当获得少量的行锁时,行锁就会自动地逐渐升级为表锁。

 

当然,所有这些的缺点就在于并发的影响:如果表上有一个 X 锁,那么其他应用程序除非使用了隔离级别 UR(未提交的读),否则都不能访问该表。如果知道独占访问不会导致问题,那么就应该尽量使用表锁。但是,即使您坚持使用行锁,也应记住,在批量插入期间,表中可能存在数千个有 X 锁的新行,所以就可能与其他使用该表的应用程序产生冲突。通过一些方法可以将这些冲突减至最少

* 确保锁的升级不会无故发生。您可能需要加大 LOCKLIST 和/或 MAXLOCKS 的值,以允许插入应用程序有足够的锁
* 对于其他的应用程序,使用隔离级别 UR。
* 对于 V8 FixPak 4,或许也可以通过 DB2_EVALUNCOMMITTED 注册表变量来减少锁冲突:如果将该变量设置为 YES,那么在很多情况下,只能获得那些符合某个谓词的行上的锁,而并不是获得被检查的所有行上的锁。
* 发出一个 COMMIT 命令以释放锁,因此如果更频繁地提交的话就足以减轻锁冲突的负担。

 

注意

* 在 V7 中,存在涉及 insert 和键锁的并发问题,但是在 V8 中,由于提供了 type-2 索引,这些问题实际上已经不见了。如果要迁移到 V8 中来,那么应该确保使用带 CONVERT 关键字的 REORG INDEXES 命令,以便将索引从 type-1 转换为 type-2。
* 在 V7 中,插入过程中可能使用 W 或 NW 锁,但是在 V8 中只有在使用了 type-1 索引或者隔离级别为 RR 的情况下才会出现这两种锁。因此,应尽可能避免这两种情况。
* 一条 insert 所据有的锁(通常是一个 X 锁)通常不会受隔离级别的影响。例如,使用隔离级别 UR 不会阻止从插入的行上获得锁。然而,如果使用了 INSERT ... SELECT,则隔离级别将影响从 SELECT 获得的锁。

 

6. 日志记录

缺省情况下,每条 insert 都会被记录下来,以用于恢复。日志记录首先被写到内存中的日志缓冲池,然后再写到日志文件,通常是在日志缓冲池已满或者发生了一次提交时写到日志文件的。对批量插入的日志记录的优化实际上就是最小化日志记录写的次数,以及使写的速度尽可能快。

这里首先考虑的是日志缓冲池的大小,这由数据库配置参数 LOGBUFSZ 来控制。该参数缺省值为 8 页或 32 K,这与大多数批量插入所需的理想日志缓冲池大小相比要小些。举个例子,对于一个批量插入,假设对于每一行的日志内容有 200 字节,则在插入了 160 行之后,日志缓冲池就将被填满。如果要插入 1000 行,因为日志缓冲池将被填满几次,再加上提交,所以大概有 6 次日志写。如果将 LOGBUFSZ 的值增加到 64 页(256K)或者更大,缓冲池就不会被填满,这样的话对于该批量插入就只有一次日志写(在提交时)。通过使用更大的 LOGBUFSZ 可以获得大约 13% 的性能提升。较大日志缓冲池的不利之处是,紧急事故恢复所花的时间可能要稍微长一点。


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理