可以通过将该表改变成 APPEND ON 来通知 DB2 在执行 INSERT 时不必搜索空槽:
ALTER TABLE OLD_RECEIPTS APPEND ON
这将使 INSERT 更快。万一银行有时要迅速地做些假帐,可以关闭 APPEND,而在 OLD_RECEIPTS 表中会暴露出一堆 20 世纪 90 年代后期执行的 INSERT、UPDATE 和 DELETE 语句。
第五列我们已经学习了一些如何对磁盘上的行进行排序的有用方法,但请记住,如果用户在乎顺序,他们必须使用 ORDER BY 语句进行指定。不使用 ORDER BY,DB2 不会保证以某种顺序传递行。维护或新发行版导致了存取计划的更改,或者单独处理器向协调程序节点传送行的速度的改变,使得任何结果集的顺序都是任意的,除非您指定了 ORDER BY 语句。列的情况基本相同,但略有差异。在 SELECT 语句中指定您想要的列顺序。SELECT * 按创建表时指定的列顺序产生列。列的顺序很重要吗?也许吧。请注意后面的信息仅适用于 Windows、Unix 和 OS/2 上的 DB2。其它平台上的列处理有所不同。此外,下面讨论的内容在任何将来的 DB2 发行版中有可能更改(尽管如果它真的更改了,则需要重要工程技术将所有在 DB2 版本 7.2 或更早版本中创建的表移为新格式)。
当您创建表时,要拥有更快的 SELECT 操作,对列进行排序没有最佳方法。然而,在创建完表时,如果知道哪些是最频繁更新的列,首先将它们列出是有好处的。当用 UPDATE 语句更新了行之后,DB2 必须将 UPDATE 的结果写到日志并立即(或最终)写到存储这行的磁盘中(通常是在刷新缓冲池时)。不必将整行写入日志;只需要将更改的列写入即可。写到日志中的是这一行的第一列,以及此后的每一行,直到 DB2 达到最后一个更改的列为止。如果客户的社会保险号是不变的,将它放到行的末尾附近。经常更改的资料(如帐户余额)应该在或者接近行的开头。偶尔更改的资料(如地址)应该放在帐户余额和社会保险号之间。
让我们看看列在磁盘上是如何布局的。如果您创建了一个只有定长列的表,将严格按照 CREATE 语句中指定的顺序安排它们:
CREATE TABLE TESTORD (COL1 INT, COL2 CHAR(5), COL3 DEC(10,2), COL4 FLOAT)
图 1.
如果表拥有变长列(如 VARCHAR),列仍然按照 CREATE TABLE 语句中指定的顺序排序,但可变数据本身在行的末尾:
CREATE TABLE TESTORD (COL1 INT, COL2 VARCHAR(5), COL3 DEC(10,2))
图 2.
如果表有长字段,它将不随每行直接插入。因为行宽受页大小限制(4K 到 32K),所以行只有一个指向长字段的指针,而将长字段与行分开放置在数据库页中:
CREATE TABLE TESTORD (COL1 INT, COL2 CLOB(100 K), COL3 DEC(10,2))
图 3.
一站式购物
索引创建了一些数据冗余,但向用户隐瞒了这一点(当用户更新表时,不必为更新索引操心,那是 DB2 的任务)。DB2 比其它许多数据库管理系统更多地依赖于索引,这主要是因为它拥有完善的优化器。数据库世界中将仅索引访问称为“一站式购物”:如果 SELECT 需要的所有数据都在索引中,则 DB2 只须读取索引即可。考虑下列表及 NAME 上的索引,NAME 是主键:
CREATE TABLE ADDRESS (NAME CHAR(20) not null, STREET CHAR(20), CITYPROV CHAR(20), POSTCODE CHAR(7), HOMEPHONE CHAR(12), WORKPHONE CHAR(12), NOTES CHAR(20)) CREATE UNIQUE INDEX NAME_INDX ON ADDRESS (NAME)
如果发出:
SELECT NAME FROM ADDRESS 或 SELECT NAME FROM ADDRESS WHERE NAME = 'Adamache, Blair'
DB2 将仅通过扫描索引来收集查询结果。如果发出:
SELECT NAME, WORKPHONE FROM ADDRESS DB2 将扫描表:索引没有提供任何好处。您可以通过从“命令中心”发出上述所有命令,并使用“Create Access Plan”图标查看 DB2 优化器对数据采取的路径来测试这些存取路径。上述的所有三个 SELECT 都进行一站式购物:单独的表或索引都能满足查询。当优化器希望使用索引,但又需要读取表以获得其它列时会怎么样呢?这个 SELECT 语句将同时需要扫描索引和读取表: SELECT NAME, WORKPHONE FROM ADDRESS WHERE NAME = 'Adamache, Blair'
如果这是一种公共访问方法(人们希望查看某人的电话号码,并通过对姓名的搜索开始),您可以告诉 DB2 在索引中包含额外的列。WORKPHONE 将不会成为主键的一部分:它只是包含在索引中,这样就可以使用仅索引访问来满足更多的查询。先从除去单列索引开始:
DROP INDEX NAME_INDX
现在,重新创建索引,并包含用户通常希望查看的额外列:
CREATE UNIQUE INDEX NAME_INDX ON ADDRESS (NAME) INCLUDE (WORKPHONE, HOMEPHONE)
请牢记,尾随的额外列越多,UPDATE 和 INSERT 花费的时间就越长:包含的每个列现在都必须在表和索引中进行更改。使用了包含索引,下列查询现在可以使用仅索引访问来运行了:
SELECT NAME, WORKPHONE FROM ADDRESS WHERE NAME = 'Adamache, Blair'
结束语
我已经向您展示了一些窍门来决定将行和列放置到哪里,让我们记住:人的任务是成为 DBA — 数据库管理员。DB2 的任务是成为数据库管理器。大多数情况下,DB2 会基于模式或根据模式创建的索引作出合理的决定。我始终强调:利用 DB2 EEE 无共享体系结构来使您的硬件物有所值。这同样适用于软件。您购买了硬件,也在软件上花了一些钱(我希望如此):DB2 优化器、数据管理器及其关系引擎。对于数据库应用程序中重要的表,上述的一些技术是值得使用的。您不必对数据库中创建的每个表都使用上述的所有或任一技术。如果有时间这样做,您可以通过编写关于 DB2 的文章和书籍来告诉别人如何调整 DB2 来谋生。
关于作者
Blair Adamache 是 IBM 多伦多实验室里有十七年工作经验的老员工。他相信如果从 1970 年到 1995 年的每次棒球赛都统计到一个关系表而每次投掷都占一行的话,那么我们将可以证明 Dwight Evans 和 Bobby Grich 应当进棒球名人堂(Baseball Hall of Fame)。






