7. 空余空间方面的考虑
分配空余空间的主要目的是使数据行的物理顺序与群集索引一致,以减少频繁重组数据的需要。此外,对行的更好的群集会使读访问的速度更快,行插入的速度也更快。然而,过多地分配空余空间可能会产生浪费的dasd空间,导致每次i/o只能传输更少的数据,缓冲池的利用效率更低,并且要扫描更多的页。
表空间和索引中空余空间的分配是由create或alter tablespace以及create或alter index语句的pctfree和freepage选项确定的。
pctfree告诉db2在装载或重组数据时,表空间或索引中的每个页要留出多少百分比的空余空间。如果没有足够的空余空间来按照恰当的顺序(也就是按群集顺序)编写行或索引,那么db2就必须将多出的数据放到另一个页上。当越来越多的记录被乱序存放时,性能就会出现问题。
freepage告诉db2在装载或重组数据时,应该过多久就分配一整页的空余空间。例如,如果指定了freepage 5,那么db2将在用数据填充了5个页之后分配一页的空余空间。如果表行大于页宽的一半,则应该使用freepage,因为在那样的环境下不能在一页上再insert一行。
是否定义带空余空间的表空间,以及分配多少的空余空间,这很大程度上取决于表空间中表的insert特征(其次是delete活动)。换句话说,这取决于将行添加到表中的频率,以及将行添加到表的什么地方。下面有4种类别:
2) 随机插入:对于已经有很多行、并且insert活动的级别很低,那么一开始可以使用默认的pctfree(对于表空间,该值是5,对于索引,该值是10)。然后使用runstats监控数据失序的程度,再考虑您期望运行reorg的频率,对pctfree进行必要的上下调整。对于insert活动级别很高的表,可能需要使用大于默认值的pctfree。对于开始为空或者只包含很少行的表(例如在新数据库的部署期间),可能需要指定一个较高的pctfree,并不时地运行一下reorg,直到这个表被填充好为止。
3) 在表的末尾插入:如果一个表中的行的长度不会增长,那么就无需分配空余空间,因为这些行是在表的末尾插入的。由于这些行是按照物理的群集顺序来写的,因此不需要运行reorg。但是,如果一个表包含可更新的varchar列,或者该表被压缩,那么有可能行的长度会增长,从而导致某一行被转移到其他页上。您可以通过对表空间执行runstats,然后检查db2编目表sysibm.systablepart的nearindref和farindref这两列来判断上述情况。如果表变得缺乏组织,那么为表空间指定一个pctfree,并继续用runstats监控位置不当(mislocated)的行。根据当前的数据以及您所观察到的趋势,对reorg的频率和pctfree的数字进行相应的调整。通过在reorg tablespace中指定indreflimit和reportonly选项,可以监控被更新的db2表中位置不当的行的数目,以及隔多远会出现这样的行。
4) 在热点(hot spot)中插入:在这种情况下,表上的插入活动很频繁,而且集中在某一个位置(或几个位置),而不是在表的末尾进行插入。这一类情况可能是最难于处理的。可以尝试增加pctfree的值。如果插入活动停留在主段(home segment)中,并且插入的行不是很长,那么可以将数行存储在相同的页中。在此情况下,另一种可以考虑的方案是使用freepage。这时有必要严密监控表变得无组织的速度,这样就可以在性能急剧下。
五、索引设计方面的考虑
索引也是一种db2对象(一个单独的vsam数据集),它由一组排好序的键组成,这些键是从相应表中的一个列或多个列抽取出来的。很多db2专家声称,只有为表空间建立恰当的索引,才是使得访问该表空间中db2数据的应用程序的性能达到最佳、最有效的效果。数年前,在i/t中dasd的成本和空间是更重要的考虑因素。随着技术的发展,通过增加更多的索引(或添加列到已有的索引中)来减少i/o,以及由此消耗的额外磁盘空间,这几年两者之间的权衡已经变得越来越有吸引力。索引所带来的主要性能好处是:
1) 提供指向表中被请求的数据行的直接指针。
2) 如果结果集要求的顺序与索引一致,则可以消除排序。
3) 如果被请求的列都包含在索引项中,则可以避免不得不读数据行的情况。
1. 分区索引
在db2 udb v7中创建分区的表空间时,db2根据create index语句的part子句将数据划分到几个分区上。那样的索引就成为所谓的分区索引,而这种分区的方法就被称为 索引控制的分区(index-controlled partitioning)。对于分区索引,建议选择不大可能改变的键列。如果对那些列进行更新,则可能导致一行从一个分区转移到另一个分区,从而降低了性能。
db2 v8一个重要的特性是表控制的分区(table-controlled partitioning)。这时,当创建分区的表时,分区的边界由create table语句决定,而不是由create index语句决定。对于索引控制的分区方法,分区的表、分区索引和群集这几个概念之间有点纠缠不清。而在表控制的分区方法中,这三个概念是各自独立的。这种增加的灵活性使您可以考虑更多潜在的设计方案,因而也增加了提高db2数据库及其应用程序性能的机会。
2. 何时建立索引
create index语句使用户可以立即建立索引,或者将索引的建立推迟到方便的时候。如果立即建立索引,则需要扫描表空间,这样要花费比较多的时间。通过指定defer,则可以推迟索引的创建。
只要有可能,应该在初次装载一个表之前创建其所有索引,因为load实用程序建立索引的效率比create index过程要高。如果需要在一个已有的(并且被填充的)表上创建一个索引,那么可以使用defer子句。然后可以在晚些时候使用rebuild index实用程序,这个实用程序与load实用程序一样,是更为有效的填充索引的方式。
3. piecesize
db2 udb v5中引入了一个新特性,这种特性使您可以将一个非分区索引(non-partitioning index,npi)拆成数块,然后控制将组成索引空间的多个数据集的大小。通过使用这些小块,可以使npi的索引页散步到多个数据集中。
通过在create或alter index语句中指定关键字piecesize,可以确定各块的大小。piecesize的值必须是2的幂,其大小可以介于256kb到64gb之间。对于常规表空间,piecesize的默认值是2gb,对于large表空间,默认值是4gb。如果npi极有可能显著增长,那么应选择一个更大的值。在为主空间和辅助空间(create index语句的priqty和secqty选项)的分配确定值时,也应该留意piecesize的值。
通过使用这个选项,可以促进并行性,从而提高npi的扫描性能。另一个好处是可以减少在读或更新的处理过程中对i/o的争用。通过指定一个较小的piecesize,可以创建更多的块,从而对块的放置有更多的控制。将这些块放在不同的i/o路径中,可以减少访问npi所需的sql操作的争用。
4. 理想的索引
通过检查应用程序中的sql语句,可以建立一种想象起来很好的索引。
1) 首先,在索引中包括where子句中的所有列,这样,就可以使用索引形成的屏蔽来拒绝结果集中不合格的行。将这些列放在索引的开始部分。这样一来,当对sql语句进行explain时,就可以产生最大的matchcols值。
2) 接下来,确保索引中这些列有适当的顺序(按照order by子句),这样可以避免排序。在进行explain时,通过检查plan_table中所有不同的sort*列,便可以确认这一点。
3) 最后,如果可能的话,将select中所有的列包括到索引当中,这样就不需要访问表中的行。这样的索引项可以提供所有被请求的数据。这在explain中就表现为indexonly = y。
在很多情况下,实现这一理想的代价太高,也不切实际,甚至是不可能的。对于一个索引中可以包括的列数,以及整个索引项的长度,都有架构上的限制(虽然这些限制已考虑到相当大的索引项长度和灵活性)。而且,也要考虑索引维护的成本。虽然建立理想化的索引可以显著提高查询性能,但是每当对db2数据库执行sql写操作(insert、update 或 delete)时,上述理想化的索引都会有负面的影响。因此,您常常可以选择实现只包括在where和order by子句中引用到的列的索引。
六、并行处理方面的考虑
这些年,db2通过实现各种并行处理的方法,已经大大提高了访问数据的性能。为了提高数据密集型只读查询的性能,db2 v3引入了查询i/o并行。在这种并行中,db2充分利用分区表空间促成的可用i/o带宽。通过这种方法,db2可以为单个i/o请求启动多个并发的i/o请求,并在多个数据分区上执行并行i/o处理。这通常可以显著减少i/o bound查询所需的时间,而代价只是稍微增加的cpu时间。
db2 v4引入了另一种并行技术,这种技术称作查询cp并行。这种方法将并行处理扩展到过程密集型(process-intensive)查询中来。通过这种方法,一条查询可以使db2生成多个任务,这些任务被并行地执行,以访问数据。分区表空间最能体现这种并行所带来的性能提高。
db2 udb v5引入了sysplex查询并行,进一步扩展了并行处理。cp并行可以在db2子系统中为一条查询使用多个任务,而sysplex查询并行这种方法使一个db2数据共享组中的所有成员可以一起处理一个查询。对于那些主要是只读形式的i/o密集型和处理器密集型查询,都可以从这种并行中得到好处。
1. 支持并行访问
db2环境中对并行的支持有一个度的问题。首先,在db2子系统级,并行访问是在安装面板dsntip4上控制的。dsntip4上的max degree选项决定了最大并行度(并行任务的最大数量)。默认值是0,这意味着对于db2可能调用的并行度没有上限。我建议您先估计z/os环境中的虚拟存储能力和局限性,这样db2就不至于创建多于虚拟存储所能处理的并行任务。
您可以通过bind plan和bind package命令的degree选项来控制db2是否利用并行处理。若指定degree(1),表示禁止并行处理,若指定degree(any),则表示支持并行处理。为获得更大的灵活性,动态sql允许通过set current degree语句在一个计划或包中更改这个选项,该语句可以控制专用寄存器中的值。
当一个计划或包与degree(any)捆绑在一起,或者current degree寄存器被设为any时,db2优化器将考虑对于最有效的顺序计划,并行是否可行。如果并行不可行,那么就选择次好的顺序计划。
2. 限定分区扫描
限定分区扫描允许db2将数据扫描限制在一个分区表空间中。根据sql谓词中的值,db2可以判断可能包含sql语句所请求的表行的最低分区和最高分区,然后将数据扫描限制在这一范围内的分区中。为了使用这种技术,sql必须提供分区索引的第一个键列上的一个谓词。
3. 并行方面的建议
为了进一步促进并行处理所能带来的性能提高,下面列出了一些需要考虑的事情:
1)尽可能均匀地对表空间分区,因为数据不整齐会对并行度产生影响。一般来说,db2根据最大物理分区的大小将表空间分成逻辑上的几块。
2) 为db2应用程序的处理分配尽可能多的中央处理器(central processor,cp),以及尽可能多的 i/o 设备和路径。
3) 对于i/o密集型查询,应确保分区的数量与可以访问该表空间的i/o路径的数量一致。
4) 对于处理器密集型查询,应确保分区的数量等于将被分配用来在数据共享组上处理查询的cp的数量。
5) 将用于表空间和索引的分区放在单独的dasd卷中,并且,如果可能的话,要隔开控制单元,以减少i/o争用。
6) 按时执行runstats实用程序,以获得分区级的统计信息。
7) 监控虚拟缓冲池的阈值和使用情况,确保提供了足够的缓冲池空间来最大化并行度。
七、缓冲池方面的考虑
1. 缓冲池的重要性
很多专家将数据库缓冲池看作db2环境中影响性能的最关键的资源。很多db2的架构和设计,其基本思想都是尽可能地避免物理i/o。
db2缓冲池由数个插槽(slot)的连续的内存组成。数据和索引页被从dasd中读出之后,便进入这些插槽,并留在其中,直到db2缓冲区管理器确定那些插槽要用于其他数据。应用程序所请求的数据出现在内存中(而不是外面的dasd上)的概率越大,总体性能就越好。实际上,这里的数据被重复使用,因而减少了应用程序对i/o的需要。
是否释放一个缓冲池槽,这是根据最近被使用(lru)原则来决定的。db2维护两个lru列表,一个用于被随机访问的页,另一个用于被顺序访问的页。这样可以防止大规模的表扫描完全支配缓冲池,并恶劣地影响随机操作。通过使用不同的阈值,db2 提供了改善缓冲池性能的灵活性。在db2 sql reference手册的第2.7.4节中对这些阈值进行了较为详细的讨论。
2. 为缓冲池设置适当的大小
缓冲池大小的指定要取决于可用存储(包括中央存储和扩展存储)的容量。我建议首先分析缓冲池的分配,然后逐渐增加缓冲池的大小,直到通过增加分配的空间已无法增加更多的吞吐量,或者直到mvs换页率已难于接受为止。为实现这一点,要使dasd i/o的数量持续下降,并不断增加vpsize,直到换页的成本超出了通过减少i/o所带来的好处为止。
早些时候,getpages的数量被认为可能是对db2正在运行的工作量的最好度量。缓冲池的目的是减少i/o(异步读通常表明需要进行预取,从性能角度来看,这样做通常是值得的。另一方面,同步读常常需要对dasd进行随机i/o,因为被请求的页不在缓冲池中)。会计报表显示对应于每个缓冲池的getpages和同步读的数量。一个被普遍接受的rot声称,如果getpages对同步读的比率小于10:1,那么应该估计对更大缓冲池的需要。
3. 多缓冲池配置
如果操作系统允许为db2缓冲池分配相当大的内存,那么使用多缓冲池的配置很可能可以提高特定应用程序或数据库的性能。然而,需要清楚的是,若有了多个缓冲池,那么对这些缓冲池使用效率的监控就变得更加重要。
下面给出了关于分配多个缓冲池的一般建议:
1) 将表空间与和它们相关的索引分放到不同的缓冲池中,以减少索引i/o。
2) 将有不同数据访问模式的数据统一放到不同的缓冲池中。批处理和查询应用程序通常要进行大量的顺序处理,而用于oltp的数据访问往往更具有随机性。这为利用各种阈值处理缓冲池中某些类型的数据访问提供了一种方法。
3) 为独立的应用程序提供一个单独的缓冲池。这就为紧密监控应用程序的性能问题或测试新的应用程序提供了一种方法。
4) 如果排序的性能在您的环境中很重要,那么需要为工作文件创建一个单独的缓冲池。
5) 对于相对较小但更新频繁的表,通过一个足够大的单独的缓冲池,也许可以同时减少读和写的i/o。
6) 为只读表(小的引用表)提供单独的缓冲池可以提高性能。
八、结束语
考虑周详的数据库设计可以提供巨大的性能收益,但是这必须在应用程序开发过程的早期便开始着手。从早期的db2开始,明智的开发人员就已经使用了前面提到的很多准则,这些准则直到现在也仍然成立。但是,db2功能的增强、其他领域中硬件和软件技术的变化将影响当前和将来的应用程序,知道这一点至关重要。当数据库性能成为开发过程中的焦点时,您的数据库设计使得为db2应用程序提供最佳性能有了更大的可能性。