分类:
2008-04-14 13:12:22
来源:数据库用户 |
3. 找到存储行的地方
DB2 使用三种算法中的一种来确定将行插入到哪里。(如果使用了多维群集(Multi-dimensional Clustering,MDC),则另当别论,我们在这里不予讨论。)
缺省模式是,DB2 搜索散布在表的各页上的自由空间控制记录(Free Space Control Records,FSCR),以找到有足够自由空间存放新行的页。显然,如果每页上的自由空间都比较少的话,就要浪费很多的搜索时间。为了应付这一点, DB2 提供了 DB2MAXFSCRSEARCH 注册表变量,以便允许将搜索范围限制为少于缺省的 5 页。
当表是通过 ALTER TABLE 以 APPEND 模式放置时,就要使用第二种算法。这样就完全避免了 FSCR 搜索,因为只需简单地将行直接放到表的末尾。
当表有群集索引(clustering index)时,就要用到最后一种算法。在这种情况下,DB2 试图将每一行插入到有相似键值的一页中。如果那一页没有空间了,DB2 就会尝试附近的页,如果附近的页也没有空间,DB2 就进行 FSCR 搜索。
如果只考虑插入时间的优化,那么使用 APPEND 模式对于批量插入是最快的一种方法,但是这种方法的效果远不如我们这里讨论的很多其他方法那么成效显著。第二好的方法应该是采用缺省算法,但是,如果在最佳环境中,更改 DB2MAXFSCRSEARCH 的值影响很小,而在一个 I/O 约束较少的环境中,这种更改所造成的影响就比较可观了。
如果有群集索引,则对 insert 的性能会有很大的负面影响,这一点也不惊奇,因为使用群集索引的目的就是通过在插入时做额外的工作来提高查询(即 select)性能的。如果的确需要群集索引,那么可以通过确保有足够的自由空间来使其对插入的影响降至最小:使用 ALTER TABLE 增加 PCTFREE,然后使用 REORG 预留自由空间。不过,如果允许太多自由空间的存在,则可能导致查询时需要读取额外的页,这反而大大违反了使用群集索引的本意。另一种选择是,在批量插入之前先删除群集索引,而后再重新创建群集索引,也许这是最优的方法(创建群集索引的开销跟创建常规索引的开销差不多,都不是很大,只是在插入时有额外的开销)。
4. 缓冲池、I/O 和页清除
每一条 insert 在执行时,都是先将新行存储在一个页中,并最终将那个页写到磁盘上。一旦像前面讨论的那样指定了页,那么在将行添加到该页之前,该页必须已经在缓冲池中。对于批量插入,大部分页都是最新指派给表的,因此让我们关注一下对新页的处理。
如果表在系统管理存储的(System Managed Storage,SMS)表空间中,当需要新页时,缺省情况下是从文件系统中分别为每一页分配空间。但是,如果对数据库运行了 db2empfa 命令,那么每个 SMS 表空间就会为新页一次性分配一个区段。我们建议运行 db2empfa 命令,并使用 32 页的区段。
对于数据库管理的存储(Database Managed Storage,DMS)表空间,空间是在创建表空间时就预先分配的,但是页的区段则是在插入处理过程中指派给表的。与 SMS 相比,DMS 对空间的预分配可以提高大约 20% 的性能 -- 使用 DMS 时,更改区段大小并没有明显的效果。
如果表上有索引,则对于每个插入的行,都要添加一个条目到每条索引。这要求在缓冲池中存在适当的索引页。晚些时候我们将讨论索引的维护,但是现在只需记住,插入时对缓冲池和 I/O 的考虑也类似地适用于索引页,对于数据页也是一样。
随着插入的进行,越来越多的页中将填入被插入的行,但是,DB2 不要求在 insert 或 Commit 后将任何新插入的或更新后的数据或索引写入到磁盘。(这是由于 DB2 的 writeahead 日志记录算法。但是有一个例外,这将在关于日志记录的小节中论述到。)然而,这些页需要在某一时刻写到磁盘上,这个时刻可能会在数据库关闭时才会轮到。 |