扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
6. 日志记录
缺省情况下,每条 insert 都会被记录下来,以用于恢复。日志记录首先被写到内存中的日志缓冲池,然后再写到日志文件,通常是在日志缓冲池已满或者发生了一次提交时写到日志文件的。对批量插入的日志记录的优化实际上就是最小化日志记录写的次数,以及使写的速度尽可能快。
这里首先考虑的是日志缓冲池的大小,这由数据库配置参数 LOGBUFSZ 来控制。该参数缺省值为 8 页或 32 K,这与大多数批量插入所需的理想日志缓冲池大小相比要小些。举个例子,对于一个批量插入,假设对于每一行的日志内容有 200 字节,则在插入了 160 行之后,日志缓冲池就将被填满。如果要插入 1000 行,因为日志缓冲池将被填满几次,再加上提交,所以大概有 6 次日志写。如果将 LOGBUFSZ 的值增加到 64 页(256K)或者更大,缓冲池就不会被填满,这样的话对于该批量插入就只有一次日志写(在提交时)。通过使用更大的 LOGBUFSZ 可以获得大约 13% 的性能提升。较大日志缓冲池的不利之处是,紧急事故恢复所花的时间可能要稍微长一点。
减少日志写的另一种可能性是对新行要插入到的那个表使用“ALTER TABLE
* 如果有一条语句失败,那么这个表将被标记为不可访问的,并且需要被删除掉。这与其他恢复问题(请参阅 SQL Reference 关于 Create Table 的讨论)一起使得 NLI 在很多情况下不能成为可行的方法。
* 在工作单元最后进行的提交,必须等到在此工作单元内涉及的所有脏页都被写到磁盘之后才能完成。这意味着这种提交要占用大量的时间。如果没有积极地进行页清除,那么在使用 NLI 的情况下,Insert 加上提交所耗费的总时间要更长一些。将 NLI 与积极的页清除一起使用的时候,可以大大减少耗时。如果使用 NLI,就要瞪大眼睛盯紧提交操作所耗费的时间。
至于提高日志写的速度,有下面一些可能性:
* 将日志与新行所要插入到的表分别放在不同的磁盘上。
* 在操作系统层将日志分放到多个磁盘。
* 考虑为日志使用原始设备(raw device),但是要注意,这样管理起来要更困难些。
* 避免使用 RAID 5,因为它不适合于写密集型(write-intensive)活动。
7. 提交
提交迫使将日志记录写到磁盘上,以保证提交的插入肯定会存在于数据库中,并且释放新行上的锁。这些都是有价值的活动,但是因为 Commit 总是要牵涉到同步 I/O(对于日志),而 insert 则不会,所以 Commit 的开销很容易高于 insert 的开销。因此,在进行批量插入时,每一行都提交一次的做法对于性能来说是很糟糕的,所以应确保不使用自动提交(对于 CLI 和 CLP 来说缺省情况正是如此)。建议大约每 1000 行提交一次:当每 1000 行而不是一两行提交一次时,性能可以提高大概 10 倍。不过,一次提交多于 1000 行只能节省少量的时间,但是一旦出现失败,恢复起来所花的时间要更多。
对上述方法的一种修正:如果 MINCOMMIT 数据库配置参数的值大于 1 (缺省值),则 DB2 就不必对每次 commit 都进行一次同步 I/O,而是等待,并试图与一组事件一起共享日志 I/O。对于某些环境来讲,这样做是有好处,但是对于批量插入常常没有作用,甚至有负作用,因此,如果要执行的关键任务是批量插入,就应该让 MINCOMMIT 的值保持为 1。
可以选择性地进行改进的地方
对于一次 insert,有几种类型的处理将自动发生。如果您的主要目标只是减少插入时间,那么最简单的方法是避免所有这些处理的开销,但是如果从总体上考虑的话,这样做未必值得。让我们依次进行讨论。
索引维护
对于插入的每一行,必须添加一个条目到表上的每个索引中(包括任何主键索引)。这一过程主要有两方面的代价:
* 遍历每个索引树,在树的每一层搜索一个页,以确定新条目必须存储在哪里(索引条目总是按键顺序存储的),这一过程所引起的 CPU 开销;
* 将所有搜索到的页读入缓冲池,并最终将每个更新后的页写到磁盘上的 I/O 开销。
更坏的场景是,在索引维护期间有大量的随机 I/O。假设要插入 10,000 行,在索引的缓冲池中有 5000 页,并且要插入的各行的键值随机分布在整个键范围内。那么,有 10,000 个这么多的叶子页(可能还有些非叶子页)需要进入缓冲池,以便对它们进行搜索和/或更新,对于一个给定的叶子页,它预先已经在缓冲池中的概率只有 10%。对于每次的 insert,需要读磁盘的概率如此之高,使得这种场景往往性能很差。
对于逐行插入,将新行添加到已有的索引中比起创建一个新索引来代价要高得多。如果是插入到一个空表,应该总是在进行了列插入之后创建索引。(注意,如果使用了 load,则应该 预先创建索引。)如果要插入到一个已经填充过的表,那么在列插入之前删除索引,并在列插入之后重新创建索引,这种方法可能是最快的,但是只有在要插入相当多的行 -- 大概大于表的 10-20% 的时候,才能这么说。如果为索引表空间使用较大的缓冲池,并且尽可能地将不同 insert 排序,以便键值是排好序的,而不是随机的,就可以帮助加快索引维护。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者