在开发过程的早期作出的很多设计决定对 DB2 应用程序和数据库的性能有着巨大的影响。本文为在 z/OS 环境中取得更好的性能提供了一些一般性的指南和建议。
作者:Fred Whitlark 来源:论坛整理 2007年11月17日
关键字: DB2
索引设计方面的考虑 索引也是一种 DB2 对象(一个单独的 VSAM 数据集),它由一组排好序的键组成,这些键是从相应表中的一个列或多个列抽取出来的。很多 DB2 专家声称,只有为表空间建立恰当的索引,才是使得访问该表空间中 DB2 数据的应用程序的性能达到最佳、最有效的效果。数年前,在 I/T 中 DASD 的成本和空间是更重要的考虑因素。随着技术的发展,通过增加更多的索引(或添加列到已有的索引中)来减少 I/O,以及由此消耗的额外磁盘空间,这几年两者之间的权衡已经变得越来越有吸引力。索引所带来的主要性能好处是: 1、提供指向表中被请求的数据行的直接指针。 2、如果结果集要求的顺序与索引一致,则可以消除排序。 3、如果被请求的列都包含在索引项中,则可以避免不得不读数据行的情况。 分区索引 在 DB2 UDB V7 中创建分区的表空间时,DB2 根据 CREATE INDEX 语句的 PART 子句将数据划分到几个分区上。那样的索引就成为所谓的分区索引,而这种分区的方法就被称为 索引控制的分区(index-controlled partitioning)。对于分区索引,建议选择不大可能改变的键列。如果对那些列进行更新,则可能导致一行从一个分区转移到另一个分区,从而降低了性能。 DB2 V8 一个重要的特性是 表控制的分区(table-controlled partitioning)。这时,当创建分区的表时,分区的边界由 CREATE TABLE 语句决定,而不是由 CREATE INDEX 语句决定。对于索引控制的分区方法,分区的表、分区索引和群集这几个概念之间有点纠缠不清。而在表控制的分区方法中,这三个概念是各自独立的。这种增加的灵活性使您可以考虑更多潜在的设计方案,因而也增加了提高 DB2 数据库及其应用程序性能的机会。 何时建立索引 CREATE INDEX 语句使用户可以立即建立索引,或者将索引的建立推迟到方便的时候。如果立即建立索引,则需要扫描表空间,这样要花费比较多的时间。通过指定 DEFER,则可以推迟索引的创建。 只要有可能,应该在初次装载一个表之前创建其所有索引,因为 LOAD 实用程序建立索引的效率比 CREATE INDEX 过程要高。如果需要在一个已有的(并且被填充的)表上创建一个索引,那么可以使用 DEFER 子句。然后可以在晚些时候使用 REBUILD INDEX 实用程序,这个实用程序与 LOAD 实用程序一样,是更为有效的填充索引的方式。 PIECESIZE DB2 UDB V5 中引入了一个新特性,这种特性使您可以将一个非分区索引(non-partitioning index,NPI)拆成 数块,然后控制将组成索引空间的多个数据集的大小。通过使用这些小块,可以使 NPI 的索引页散步到多个数据集中。 通过在 CREATE 或 ALTER INDEX 语句中指定关键字 PIECESIZE,可以确定各块的大小。PIECESIZE 的值必须是 2 的幂,其大小可以介于 256 KB 到 64 GB 之间。对于常规表空间,PIECESIZE 的默认值是 2 GB,对于 LARGE 表空间,默认值是 4 GB。如果 NPI 极有可能显著增长,那么应选择一个更大的值。在为主空间和辅助空间(CREATE INDEX 语句的 PRIQTY 和 SECQTY 选项)的分配确定值时,也应该留意 PIECESIZE 的值。 通过使用这个选项,可以促进并行性,从而提高 NPI 的扫描性能。另一个好处是可以减少在读或更新的处理过程中对 I/O 的争用。通过指定一个较小的 PIECESIZE,可以创建更多的块,从而对块的放置有更多的控制。将这些块放在不同的 I/O 路径中,可以减少访问 NPI 所需的 SQL 操作的争用。 理想的索引 通过检查应用程序中的 SQL 语句,可以建立一种想象起来很好的索引。 首先,在索引中包括 WHERE 子句中的所有列,这样,就可以使用索引形成的屏蔽来拒绝结果集中不合格的行。将这些列放在索引的开始部分。这样一来,当对 SQL 语句进行 EXPLAIN 时,就可以产生最大的 MATCHCOLS 值。 接下来,确保索引中这些列有适当的顺序(按照 ORDER BY 子句),这样可以避免排序。在进行 EXPLAIN 时,通过检查 PLAN_TABLE 中所有不同的 SORT* 列,便可以确认这一点。 最后,如果可能的话,将 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 密集型和处理器密集型查询,都可以从这种并行中得到好处。 支持并行访问 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 优化器将考虑对于最有效的顺序计划,并行是否可行。如果并行不可行,那么就选择次好的顺序计划。 限定分区扫描 限定分区扫描允许 DB2 将数据扫描限制在一个分区表空间中。根据 SQL 谓词中的值,DB2 可以判断可能包含 SQL 语句所请求的表行的最低分区和最高分区,然后将数据扫描限制在这一范围内的分区中。为了使用这种技术,SQL 必须提供分区索引的第一个键列上的一个谓词。 并行方面的建议 为了进一步促进并行处理所能带来的性能提高,下面列出了一些需要考虑的事情: 1、尽可能均匀地对表空间分区,因为数据不整齐会对并行度产生影响。一般来说,DB2 根据最大物理分区的大小将表空间分成逻辑上的几块。 2、为 DB2 应用程序的处理分配尽可能多的中央处理器(central processor,CP),以及尽可能多的 I/O 设备和路径。 3、对于 I/O 密集型查询,应确保分区的数量与可以访问该表空间的 I/O 路径的数量一致。 4、对于处理器密集型查询,应确保分区的数量等于将被分配用来在数据共享组上处理查询的 CP 的数量。 将用于表空间和索引的分区放在单独的 DASD 卷中,并且,如果可能的话,要隔开控制单元,以减少 I/O 争用。 5、按时执行 RUNSTATS 实用程序,以获得分区级的统计信息。 6、监控虚拟缓冲池的阈值和使用情况,确保提供了足够的缓冲池空间来最大化并行度。