四、表空间与表设计方面的考虑 1. 记录大小和页宽
固定长度的记录要优于可变长度的记录,因为
DB2代码专门为处理固定长度的记录进行优化。如果记录是固定长度的,那么就无需将其从存储它的初始页面转移到其他地方。而对于可变长度的记录,其长度可能会变得不再适合初始页,因此必须将其转移到其他页。之后,每当需要访问该记录时,就必须发生额外的页引用。
DB2 UDB V8中的一种新特性允许在需要的时候修改(ALTER)某一列的宽度,这样一来,即使您不能确定将来数据长度的增长情况,也不再需要创建可变长度的记录。
一个页中所能存放的记录的数目也是值得考虑的一个方面。
DB2为页宽提供了很多选项(4KB、8KB、16KB和32KB)。一开始的时候,可以选择默认选项(4KB),如果行的长度很小,或者对数据的访问基本上是随机的,则更应该选择这一选项。不过,在有些情况下,则需要考虑使用更大的页宽。如果一个表中各行的长度要大于4KB,那么就需要使用更大的页宽,因为
DB2不支持跨页(spanned)记录。
还有一些情况下,对于一条固定长度的记录,其总长度可能刚好比4KB的一半大一点点,这时一个页只能容纳一条记录。对于刚好比页宽的 1/3、1/4 大一点点的记录,情形也是类似的。这种设计不仅浪费DASD空间,而且,对于很多
DB2操作,还需要消耗更多的资源。因此,对于这一类的记录,应该考虑使用更大的页宽,这样浪费的空间相对要少一些。
其他可能的页宽是8KB、16KB和32KB。页宽不是在CREATE TABLE语句中直接指定的。相反,表的页宽是由相应的缓冲池的页宽来确定的,这个缓冲池也就是为包含该表的表空间所指定的缓冲池。要了解更多细节,请参考
DB2 SQL Reference手册中的CREATE TABLESPACE语句。
2. 反规范化方面的考虑
逻辑数据模型是数据的理想蓝图。物理数据模型才是对数据的现实的实现。规范化只关注数据的意义,而没有考虑对于访问数据的应用程序的性能需求。完全规范化的数据库设计在性能方面要受到质疑。
这种性能问题的最常见的例子是连接(join)操作。通常,规范化过程最终将相关的信息放入不同的表中。于是应用程序需要从多个这样的表中访问数据。关系数据库为SQL语句提供了从一个以上的表中访问信息的能力,这是通过 连接多个表来完成的。连接操作可能要消耗大量的资源和时间,这取决于表的数量以及这些表各自的长度。
像I/T中的很多事情一样, 这里也可以考虑一种权衡的方法。对于具有经常被请求的列的多个表,一种是复制其中的数据,一种是执行表连接,两者谁的成本更高呢?在逻辑数据库设计过程中,您可以毫无保留地规范化数据模型,然后再加入一定程度的反规范化,作为潜在的性能调优的一种选择。如果您确实打算反规范化,那么一定要为此制作完整文档:较详细地描述您所采取的反规范化步骤背后的原因。
3. 设计大型的表
访问非常大的
DB2表时,相应地要消耗很多的资源:CPU、内存和I/O。在设计大型表的时候,为了提高性能,用户可以做的最重要的两件事是:
1) 实现分区。
2) 创建有用的索引。
下面将更详细地讨论这两个话题。
4. 使用分段的或分区的表空间
如果数据包括LOB,那么用户就必须创建LOB表空间。对于非LOB数据,一般需要在分区表空间和分段表空间之间进行选择,这很大程度上取决于要存储的数据量,在一定长度上也取决于相关应用程序所需的数据访问类型。简单表空间已经很少被推荐了。
下面列出了分段表空间相对于简单表空间的一些性能优势:
1) 对于包含多个表的表空间,当
DB2取得用于某一个表的锁时,这个锁不会影响对其他表的段的访问。
2) 当
DB2扫描一个表时,只是访问与那个表相关的段。而且,空段中的页不会被提取。
3) 如果一个表被删除,在执行COMMIT之际,它的段就立即可以为其他表所用,而不需要执行REORG实用程序。
4) 如果一个表中的所有行都被删除(即 mass delete),则在执行COMMIT之际,该表所有的段就立即可以为其他表所用,而不需要执行REORG实用程序。
5) mass delete执行起来要高效得多,并且要写的日志信息也更少一些。
6) COPY实用程序不会复制那些由mass delete操作或删除(DROP)一个表所造成的空页。
当表达到一定大小时,通过实现分区表空间可以提高易管理性和性能。如果预见到这样的增长,那么明智的做法是,在设计和创建表空间时将其定义为分区的。下面列出了分区表空间可以提供的一些潜在的优势:
1) 并行性:您可以使用
DB2 UDB目前所使用的三种并行方式。查询并行(多条I/O路径)是在
DB2 V3中引入的。Sysplex查询并行(一个
DB2数据共享组中的多用户和多任务)是在
DB2 UDB V5中引入的。到现在,
DB2已得到极大的发展,并大大地增强了那些处理分区表空间的
DB2应用程序的并行处理能力。通过增加一定的CPU时间,可以大大减少这些查询所需的时间。
2) 对部分数据进行操作:分区表空间允许
DB2实用程序一次处理一个分区的数据,这样其他任务或应用程序就可以并发地对其他分区进行访问。按照类似的方式,您可以将mass UPDATE、DELETE或INSERT操作拆成多个不同的任务。除了增加可用性以外,这种技术还可以为减少完成这种
DB2工作所需的时间提供潜力。
3) 对频繁访问的数据有更快的访问速度:如果分区索引可以将访问更频繁的行与表中其他的行分开来,那么就可以将这些数据放入到它们专用的分区中,并使用更高速的DASD设备。
通常,表越大,就越有理由将其创建为分区的表。但有时候为较小的表创建分区表空间也很有利。当将 查找(lookup)表与其他较大的分区的表相连接时,通过将查找表也进行分区,可以最大化并行度。
如果在连接谓词中使用分区键(partitioning key),最后还有一点考虑需要顾及。需要按分区键进行连接的表应该有相同数量的分区,并且应该在相同的值上断开。
5. 数据压缩
DB2提供了压缩一个表空间或分区中的数据的能力。这是通过在CREATE TABLESPACE语句中指定COMPRESS YES选项,然后对表空间执行LOAD或REORG实用程序来实现的。通过用较短的字符串替换经常出现的长字符串,可以压缩数据。这时会建立一个字典,其中包含了映射原始的长字符串与它们的替换值的信息。
在数据被存储之前压缩数据,以及在从外部存储设备读出数据时将数据解压,这都需要使用一定的CPU资源。但是,数据压缩也可以为性能带来好处,因为可以在更少的空间(包括DASD和缓冲池中的空间)中存储更多的数据,与未压缩的数据相比,这样可以减少同步读,减少I/O等。
在决定是否压缩一个表空间或分区时,要考虑下面一些事情:
1) 行的长度:行的长度越大(尤其是它接近页宽时),压缩的效率就越低。在
DB2中,行不能跨页,您可能无法实现足够的压缩来使一页可以容纳多行。
2) 表的长度:对于更大的表空间,压缩更为有效。对于非常小的表,压缩字典的大小(8KB到64KB)有可能会抵消掉通过压缩所节省出来的空间。
3) 数据中的模式:对于特定的表空间或分区,数据中重复出现的模式的出现频率将决定压缩的效果。有大量重复字符串的数据有巨大的压缩潜力。
4) 对压缩的估计:
DB2提供了一个独立的实用程序DSN1COMP,通过执行该实用程序可以判断压缩数据的效果。要了解关于运行该实用程序的更多信息,请参考
DB2 Utilities Guide and Reference手册。
5) 处理成本: 压缩和解压数据时,要消耗一定的CPU资源。与使用
DB2软件模拟程序相比,使用IBM的同步数据压缩硬件可以大大减少所消耗的CPU资源(当
DB2启动时,它将判断硬件压缩特性是否可用)。
6) 更好的字典:当使用LOAD实用程序来建立压缩字典时,
DB2使用所装载的前n行(其中n取决于数据的压缩程度)来决定字典的内容。REORG使用一种抽样技术来建立字典。它不仅使用所装载的前n行,而且还会对该实用程序执行期间剩下的UNLOAD阶段中的行进行抽样。因此,REORG常常可以产生更能代表整个表空间或分区中的数据的字典。
如果您的环境可以从压缩中得到好处,通常我们建议压缩那些
DB2表空间和分区,因为由于更少空间容纳更多数据所带来的性能优势几乎总是大于压缩和解压数据时所需的CPU资源消耗。
6. 装载大型的表
当处理大量的数据时,一开始将数据装载到表中时可能会遇到性能问题。为了在装载过程中实现并行性,可以手动地创建多个LOAD任务,每个分区对应一个任务,或者,也可以在单个LOAD实用程序中装载多个分区。每个分区都展开在I/O子系统上,从而更易于达到最佳的并行度。
为了获得最佳性能,在LOAD语句中指定SORTKEYS参数也很重要。这将指示
DB2将索引键传递给内存中的排序程序,而不是再次将这些键写到DASD上的排序工作文件中,然后从中读取这些键。SORTKEYS还允许装载和排序之间的重叠,因为排序是作为一个单独的任务运行的。
下面给出了关于装载大型表的其他建议:
1) 一次只LOAD一个表。
2) 如果可能,为那些预计将历时最长的任务提供较高的优先级。
3) 将工作分布在sysplex上。
4) 将辅助索引拆分成数块,以实现并行性(请参阅下面题为PIECESIZE的讨论)。
5) 在开始装载数据时,指定LOG NO(用以防止日志记录,以及节省日志记录所消耗的大量资源),然后在成功装载数据之后运行一个映像拷贝。
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种类别:
1) 只读表:如果对于一个表没有任务更新活动,那么可以将其定义为没有空余空间。而且,也没有任何必要去运行REORG实用程序。
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。这时有必要严密监控表变得无组织的速度,这样就可以在性能急剧下降之前运行REORG。