DB2 工作负载
磁盘 I/O 常常是影响响应时间的最大因素,但是通过查看 GETPAGE (GP) 请求,更容易理解底层的性能问题。当监控 DB2 活动和分析报告时,GETPAGE 的数量也许是 DB2 总体工作负载的最好的指示器。
某个安装环境下的很多 DB2 工作都可以无异议地归为以下几类:
事务: 事务是在事务管理器(例如 CICS 和 IMS/TM)控制下运行的程序。其中的 SQL 通常比较简单,但是事务量比较重。事务必须为用户提供极好的响应时间,这样应用程序才不致于要长时间地等待它们所需的资源。通常,第一个调用事务的用户将承受读取索引和数据页的成本。随后的用户则常常可以发现有些资源已经在缓冲池中。
查询: 查询也是程序,常常在需要决策支持时执行它。其中的 SQL 可能非常复杂,但是工作量常常远不及事务。查询的用户常常要等上数分钟甚至数小时,这取决于为了产生用户所请求的结果集,需要对多少数据进行搜索。查询常常要引起对整个表的扫描,而对结果排序是这种类型的工作负载的另一种常见特征。
批处理和实用程序: 批处理和实用程序通常处理大量的数据,并且常常以一种连续的方式处理数据。这些程序在给定的 窗口中完成它们的处理,这一点很重要。批处理和实用程序往往是各种系统资源的消费大户,一旦它们挤在一起,常常会使工作负载逐步上升。
规范化
规范化是分析应用程序所需的数据实体,然后将这些数据实体转化成一组设计良好的结构的一个格式化的过程。逻辑数据模型的一般设计目标是正确性、一致性、非冗余和简单性。而且,关系理论的信条也要求数据库要经过 规范化。
有一些按照连续编号排列的规则(也叫 范式(form))可以用来很详细地定义规范化数据。大多数专家都会建议设计者尽量遵从前三条规则,由此得到的数据就可以说是符合 第三范式。
而将一个表 反规范化(de-normalize)的意思是,违反该表之前遵从的一种或多种范式,从而修改规范化的设计。这种反标准化的过程常常是由于性能的原因而进行的。在大多数以关系数据库为主题的书籍当中,都可以找到关于规范化的更详细的信息。
DB2 表空间类型
在一个定义好的 DB2 数据库中,实际的表必须在称作 表空间(table space)的 DB2 对象中创建。用户可以在 DB2 中定义 4 种不同的表空间:
简单表空间:简单表空间可以包含一个以上的 DB2 表。这种表空间由页构成,每个页可以包含该表空间中定义的任何表中的行。
分段表空间: 分段表空间可以包含一个以上的 DB2 表。这种表空间由页组构成,页组被称作 段(segment)。每个段只能包含该表空间中定义的一个表中的行。
分区表空间:分区表空间只能包含一个表。根据 分区(partitioning)索引的键范围,这种表空间被分成数个分区。每个分区都被看作一个独立的实体,允许 SQL 和 DB2 实用程序对其进行并发处理。
LOB 表空间: LOB 表空间只用于 LOB(大型对象)数据。LOB 包括三种数据类型:BLOB(二进制大型对象)、CLOB(字符大型对象)和 DBCLOB(双字节字符大型对象)。
表空间与表设计方面的考虑
记录大小和页宽
固定长度的记录要优于可变长度的记录,因为 DB2 代码专门为处理固定长度的记录进行优化。如果记录是固定长度的,那么就无需将其从存储它的初始页面转移到其他地方。而对于可变长度的记录,其长度可能会变得不再适合初始页,因此必须将其转移到其他页。之后,每当需要访问该记录时,就必须发生额外的页引用。DB2 UDB V8 中的一种新特性允许在需要的时候修改(ALTER)某一列的宽度,这样一来,即使您不能确定将来数据长度的增长情况,也不再需要创建可变长度的记录。
一个页中所能存放的记录的数目也是值得考虑的一个方面。DB2 为页宽提供了很多选项(4 KB、8 KB、16 KB 和 32 KB)。一开始的时候,可以选择默认选项(4 KB),如果行的长度很小,或者对数据的访问基本上是随机的,则更应该选择这一选项。不过,在有些情况下,则需要考虑使用更大的页宽。如果一个表中各行的长度要大于 4 KB,那么就需要使用更大的页宽,因为 DB2 不支持 跨页(spanned)记录。
还有一些情况下,对于一条固定长度的记录,其总长度可能刚好比 4 KB 的一半大一点点,这时一个页只能容纳一条记录。对于刚好比页宽的 1/3、1/4 大一点点的记录,情形也是类似的。这种设计不仅浪费 DASD 空间,而且,对于很多 DB2 操作,还需要消耗更多的资源。因此,对于这一类的记录,应该考虑使用更大的页宽,这样浪费的空间相对要少一些。
其他可能的页宽是 8 KB、16 KB 和 32 KB。页宽不是在 CREATE TABLE 语句中直接指定的。相反,表的页宽是由相应的缓冲池的页宽来确定的,这个缓冲池也就是为包含该表的表空间所指定的缓冲池。要了解更多细节,请参考 DB2 SQL Reference手册中的 CREATE TABLESPACE 语句。
反规范化方面的考虑
逻辑数据模型是数据的 理想
数据压缩
DB2 提供了压缩一个表空间或分区中的数据的能力。这是通过在 CREATE TABLESPACE 语句中指定 COMPRESS YES 选项,然后对表空间执行 LOAD 或 REORG 实用程序来实现的。通过用较短的字符串替换经常出现的长字符串,可以压缩数据。这时会建立一个字典,其中包含了映射原始的长字符串与它们的替换值的信息。
在数据被存储之前压缩数据,以及在从外部存储设备读出数据时将数据解压,这都需要使用一定的 CPU 资源。但是,数据压缩也可以为性能带来好处,因为可以在更少的空间(包括 DASD 和缓冲池中的空间)中存储更多的数据,与未压缩的数据相比,这样可以减少同步读,减少 I/O 等。
在决定是否压缩一个表空间或分区时,要考虑下面一些事情:
行的长度: 行的长度越大(尤其是它接近页宽时),压缩的效率就越低。在 DB2 中,行不能跨页,您可能无法实现足够的压缩来使一页可以容纳多行。
表的长度: 对于更大的表空间,压缩更为有效。对于非常小的表,压缩字典的大小(8 KB 到 64 KB)有可能会抵消掉通过压缩所节省出来的空间。
数据中的模式: 对于特定的表空间或分区,数据中重复出现的模式的出现频率将决定压缩的效果。有大量重复字符串的数据有巨大的压缩潜力。
对压缩的估计: DB2 提供了一个独立的实用程序 DSN1COMP,通过执行该实用程序可以判断压缩数据的效果。要了解关于运行该实用程序的更多信息,请参考 DB2 Utilities Guide and Reference 手册。
处理成本: 压缩和解压数据时,要消耗一定的 CPU 资源。与使用 DB2 软件模拟程序相比,使用 IBM 的同步数据压缩硬件可以大大减少所消耗的 CPU 资源(当 DB2 启动时,它将判断硬件压缩特性是否可用)。
更好的字典: 当使用 LOAD 实用程序来建立压缩字典时,DB2 使用所装载的前 n 行(其中 n 取决于数据的压缩程度)来决定字典的内容。REORG 使用一种抽样技术来建立字典。它不仅使用所装载的前 n 行,而且还会对该实用程序执行期间剩下的 UNLOAD 阶段中的行进行抽样。因此,REORG 常常可以产生更能代表整个表空间或分区中的数据的字典。
如果您的环境可以从压缩中得到好处,通常我们建议
索引设计方面的考虑
索引也是一种 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 设备和路径。
缓冲池方面的考虑
缓冲池的重要性
很多专家将数据库缓冲池看作 DB2 环境中影响性能的最关键的资源。很多 DB2 的架构和设计,其基本思想都是尽可能地避免物理 I/O。
DB2 缓冲池由数个 插槽(slot)的连续的内存组成。数据和索引页被从 DASD 中读出之后,便进入这些插槽,并留在其中,直到 DB2 缓冲区管理器确定那些插槽要用于其他数据。应用程序所请求的数据出现在内存中(而不是外面的 DASD 上)的概率越大,总体性能就越好。实际上,这里的数据被重复使用,因而减少了应用程序对 I/O 的需要。
是否释放一个缓冲池槽,这是根据最近被使用(LRU)原则来决定的。DB2 维护两个 LRU 列表,一个用于被随机访问的页,另一个用于被顺序访问的页。这样可以防止大规模的表扫描完全支配缓冲池,并恶劣地影响随机操作。通过使用不同的阈值,DB2 提供了改善缓冲池性能的灵活性。在 DB2 SQL Reference 手册的第 2.7.4 节中对这些阈值进行了较为详细的讨论。
为缓冲池设置适当的大小
缓冲池大小的指定要取决于可用存储(包括中央存储和扩展存储)的容量。我建议首先分析缓冲池的分配,然后逐渐增加缓冲池的大小,直到通过增加分配的空间已无法增加更多的吞吐量,或者直到 MVS 换页率已难于接受为止。为实现这一点,要使 DASD I/O 的数量持续下降,并不断增加 VPSIZE,直到换页的成本超出了通过减少 I/O 所带来的好处为止。
早些时候,GETPAGES 的数量被认为可能是对 DB2 正在运行的工作量的最好度量。缓冲池的目的是减少 I/O(异步读通常表明需要进行预取,从性能角度来看,这样做通常是值得的。另一方面,同步读常常需要对 DASD 进行随机 I/O,因为被请求的页不在缓冲池中)。会计报表显示对应于每个缓冲池的 GETPAGES 和同步读的数量。一个被普遍接受的 ROT 声称,如果 GETPAGES 对同步读的比率小于 10:1,那么应该估计对更大缓冲池的需要。
多缓冲池配置
如果操作系统允许为 DB2 缓冲池分配相当大的内存,那么使用多缓冲池的配置很可能可以提高特定应用程序或数据库的性能。然而,需要清楚的是,若有了多个缓冲池,那么对这些缓冲池使用效率的监控就变得更加重要。
下面给出了关于分配多个缓冲池的一般建议:
1、将表空间与和它们相关的索引分放到不同的缓冲池中,以减少索引 I/O。
2、将有不同数据访问模式的数据统一放到不同的缓冲池中。批处理和查询应用程序通常要进行大量的顺序处理,而用于 OLTP 的数据访问往往更具有随机性。这为利用各种阈值处理缓冲池中某些类型的数据访问提供了一种方法。
3、为独立的应用程序提供一个单独的缓冲池。这就为紧密监控应用程序的性能问题或测试新的应用程序提供了一种方法。
4、如果排序的性能在您的环境中很重要,那么需要为工作文件创建一个单独的缓冲池。
5、对于相对较小但更新频繁的表,通过一个足够大的单独的缓冲池,也许可以同时减少读和写的 I/O。
6、为只读表(小的引用表)提供单独的缓冲池可以提高性能。
结束语
考虑周详的数据库设计可以提供巨大的性能收益,但是这必须在应用程序开发过程的早期便开始着手。从早期的 DB2 开始,明智的开发人员就已经使用了前面提到的很多准则,这些准则直到现在也仍然成立。但是,DB2 功能的增强、其他领域中硬件和软件技术的变化将影响当前和将来的应用程序,知道这一点至关重要。当数据库性能成为开发过程中的焦点时,您的数据库设计使得为 DB2 应用程序提供最佳性能有了更大的可能性。