怎样在DB2中提高Insert性能的技巧(二)

日期: 2009-04-02 来源:TechTarget中国 英文

  下面是关于该话题的其他一些建议:

  如果可能的话,让客户机与要存取的数据库使用相同的代码页,以避免在服务器上的转换代价。数据库的代码页可以通过运行“getdbcfgfor”来确定。

  在某些情况下,CLI会自动执行数据类型转换,但是这样同时也会带来看不见的(小小的)性能损耗。因此,尽量使插入值直接处于与相应列对应的格式。

  将应用程序中与插入相关的设置开销最小化。例如,当在CLI中使用数组插入时,对于整个一组插入,应该尽量保证对于每一列只执行一次SQLBindParameter,而不是对每一组数组内容都执行一次。对于个体来说,这些调用的代价并不高,但是这些代价是累积的。

  3.找到存储行的地方

  DB2使用三种算法中的一种来确定将行插入到哪里。(如果使用了多维群集(Multi-dimensionalClustering,MDC),则另当别论,我们在这里不予讨论。)
  
  缺省模式是,DB2搜索散布在表的各页上的自由空间控制记录(FreeSpaceControlRecords,FSCR),以找到有足够自由空间存放新行的页。显然,如果每页上的自由空间都比较少的话,就要浪费很多的搜索时间。为了应付这一点,DB2提供了DB2MAXFSCRSEARCH注册表变量,以便允许将搜索范围限制为少于缺省的5页。

  当表是通过ALTERTABLE以APPEND模式放置时,就要使用第二种算法。这样就完全避免了FSCR搜索,因为只需简单地将行直接放到表的末尾。

  当表有群集索引(clusteringindex)时,就要用到最后一种算法。在这种情况下,DB2试图将每一行插入到有相似键值的一页中。如果那一页没有空间了,DB2就会尝试附近的页,如果附近的页也没有空间,DB2就进行FSCR搜索。

  如果只考虑插入时间的优化,那么使用APPEND模式对于批量插入是最快的一种方法,但是这种方法的效果远不如我们这里讨论的很多其他方法那么成效显着。第二好的方法应该是采用缺省算法,但是,如果在最佳环境中,更改DB2MAXFSCRSEARCH的值影响很小,而在一个I/O约束较少的环境中,这种更改所造成的影响就比较可观了。

  如果有群集索引,则对insert的性能会有很大的负面影响,这一点也不惊奇,因为使用群集索引的目的就是通过在插入时做额外的工作来提高查询(即select)性能的。如果的确需要群集索引,那么可以通过确保有足够的自由空间来使其对插入的影响降至最小:使用ALTERTABLE增加PCTFREE,然后使用REORG预留自由空间。不过,如果允许太多自由空间的存在,则可能导致查询时需要读取额外的页,这反而大大违反了使用群集索引的本意。另一种选择是,在批量插入之前先删除群集索引,而后再重新创建群集索引,也许这是最优的方法(创建群集索引的开销跟创建常规索引的开销差不多,都不是很大,只是在插入时有额外的开销)。

  4.缓冲池、I/O和页清除

  每一条insert在执行时,都是先将新行存储在一个页中,并最终将那个页写到磁盘上。一旦像前面讨论的那样指定了页,那么在将行添加到该页之前,该页必须已经在缓冲池中。对于批量插入,大部分页都是最新指派给表的,因此让我们关注一下对新页的处理。

  如果表在系统管理存储的(SystemManagedStorage,SMS)表空间中,当需要新页时,缺省情况下是从文件系统中分别为每一页分配空间。但是,如果对数据库运行了db2empfa命令,那么每个SMS表空间就会为新页一次性分配一个区段。我们建议运行db2empfa命令,并使用32页的区段。

  对于数据库管理的存储(DatabaseManagedStorage,DMS)表空间,空间是在创建表空间时就预先分配的,但是页的区段则是在插入处理过程中指派给表的。与SMS相比,DMS对空间的预分配可以提高大约20%的性能–使用DMS时,更改区段大小并没有明显的效果。

  如果表上有索引,则对于每个插入的行,都要添加一个条目到每条索引。这要求在缓冲池中存在适当的索引页。晚些时候我们将讨论索引的维护,但是现在只需记住,插入时对缓冲池和I/O的考虑也类似地适用于索引页,对于数据页也是一样。

  随着插入的进行,越来越多的页中将填入被插入的行,但是,DB2不要求在insert或Commit后将任何新插入的或更新后的数据或索引写入到磁盘。(这是由于DB2的writeahead日志记录算法。但是有一个例外,这将在关于日志记录的小节中论述到。)然而,这些页需要在某一时刻写到磁盘上,这个时刻可能会在数据库关闭时才会轮到。

  一般来说,对于批量插入,您会希望积极地进行异步页清除(asynchronouspagecleANIng),这样在缓冲池中就总有可用于新页的空余位置。页清除率,或者说总缺页率,可能导致计时上的很大不同,使得性能比较容易产生误解。例如,如果使用100,000页的缓冲池,并且不存在页清除,则批量插入在结束前不会有任何新的或更改过的(“脏的”)页写到磁盘上,但是随后的操作(例如选择,甚至乎关闭数据库)都将被大大推迟,因为这时有至多100,000个在插入时产生的脏页要写到磁盘上。另一方面,如果在同一情况下进行了积极的页清除,则批量插入过程可能要花更长的时间,但是此后缓冲池中的脏页要少一些,从而使得随后的任务执行起来性能更佳。至于那些结果中到底哪个要更好些,我们并不是总能分得清,但是通常来说,将所有脏页都存储在缓冲池中是不可能的,所以为了取得最佳性能,采取有效的页清除是有必要的。

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

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

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

  确保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种情况:

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

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

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

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

  确保锁的升级不会无故发生。您可能需要加大LOCKLIST和/或MAXLOCKS的值,以允许插入应用程序有足够的锁。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

相关推荐