表分区功能是一种数据组织方案,即,表数据根据一个或多个表列中的值分布到多个存储对象(称为数据分区或范围)中。每个数据分区都是单独存储的。这 些存储对象可以在不同的表空间中,也可以在相同表空间中。按照 CREATE TABLE 语句的 PARTITION BY 子句中指定那样将表数据分区。此定义中使用的列被称为表分区键列。DB2 表分区功能与 Informix® Dynamic Server 和 Informix Extended Parallel Server 提供的数据分段组织方法相对应。
Informix 方法
Informix 支持若干种数据组织方案,在 Informix 产品中,这些方案称为分段。其中一种较常使用的分段类型是 FRAGMENT BY EXPRESSION。这种类型的分段的工作方式与 CASE 语句非常相似,其中有一个与表的每个分段相关联的表达式。检查这些表达式以便确定行的放置位置。
Informix 与 DB2 数据库系统的比较
DB2 数据库提供了丰富的补充功能,这些功能与 Informix 数据组织方案直接对应,这使客户能够相对容易地从 Informix 语法转换为 DB2 语法。DB2 数据库管理器将生成列与 CREATE TABLE 语句的 PARTITION BY RANGE 子句配合使用,以处理复杂的 Informix 方案。表 78 对 Informix 和 DB2 数据库产品中使用的数据组织方案作了比较。
表 78. 所有 Informix 与 DB2 数据组织方案的映射
数据组织方案 |
Informix 语法 |
DB2 版本 9.1 语法 |
|
FRAGMENT BY EXPRESSION |
PARTITION BY RANGE |
|
FRAGMENT BY ROUND ROBIN |
没有语法:DB2 数据库管理器自动在容器之间分布数据 |
|
FRAGMENT BY RANGE |
PARTITION BY RANGE |
- Informix:系统定义的散列
- DB2:数据库分区
|
FRAGMENT BY HASH |
DISTRIBUTE BY HASH |
- Informix:HYBRID
- DB2:在进行表分区的情况下进行数据库分区
|
FRAGMENT BY HYBRID |
DISTRIBUTE BY HASH 和 PARTITION BY RANGE |
|
不适用 |
ORGANIZE BY DIMENSION |
示例
下列示例详细说明了在 DB2 中如何实现与任何使用表达式的 Informix 分段方案等同的结果。
示例 1:下面这个基本的 Create Table 语句显示了 Informix 分段以及等同的 DB2 数据库系统表分区语法:
Informix 语法:
CREATE TABLE demo(a INT) FRAGMENT BY EXPRESSION
a = 1 IN db1,
a = 2 IN db2,
a = 3 IN db3;
DB2 语法:
CREATE TABLE demo(a INT) PARTITION BY RANGE(a)
(STARTING(1) IN db1,
STARTING(2) IN db2,
STARTING(3) ENDING(3) IN db3);
Informix XPS 支持称为 hybrid 的两层分段方案,在此方案中,使用一个表达式来在协作服务器之间分布数据,并使用第二个表达式来在协作服务器内分布数据。这使所有协作服务器都能够参与查 询(即,在所有协作服务器上都有数据),并使查询能够利用数据分区消除功能的优势。
通过结合使用 CREATE TABLE 语句的 DISTRIBUTE BY 和 PARTITION BY 子句,DB2 数据库系统实现了与 Informix hybrid 等同的组织方案。
示例 2:以下示例显示了组合子句的语法:
Informix 语法
CREATE TABLE demo(a INT, b INT) FRAGMENT BY HYBRID HASH(a)
EXPRESSION b = 1 IN dbsl1,
b = 2 IN dbsl2;
DB2 语法
CREATE TABLE demo(a INT, b INT) IN dbsl1, dbsl2
DISTRIBUTE BY HASH(a),
PARTITION BY RANGE(b) (STARTING 1 ENDING 2 EVERY 1);
此外,可以使用多维集群来进一步组织数据:
CREATE TABLE demo(a INT, b INT, c INT) IN dbsl1, dbsl2
DISTRIBUTE BY HASH(a),
PARTITION BY RANGE(b) (STARTING 1 ENDING 2 EVERY 1)
ORGANIZE BY DIMENSIONS(c);
这样,列 a 值相同的所有行都在同一个数据库分区中。所有列 b 值相同的行都在同一个表空间中。对于具有给定的 a 和 b 值的行,会将再具有相同 c 值的所有行集中到一个磁盘上。此方法非常适合于 OLAP 类型的下寻操作,这是因为,仅需扫描单个数据库分区上单个表空间中的一个或数个扩展数据块就可以满足此类查询。
应用表分区以解决常见的应用程序问题
下列各节讨论如何应用各种 DB2 表分区功能以解决常见的应用程序问题。每一节都特别侧重于采取最佳措施来将各种 Informix 分段方案映射到等同的 DB2 表分区方案。
创建简单数据分区范围时的注意事项
其中一种最常见的表分区应用是根据日期键对大型事实表进行分区。如果需要创建大小统一的日期范围,请考虑使用自动生成的 CREATE TABLE 语法格式。
示例
示例 1:以下示例显示自动生成的语法格式:
CREATE TABLE orders
(
l_orderkey DECIMAL(10,0) NOT NULL,
l_partkey INTEGER,
l_suppkey INTEGER,
l_linenumber INTEGER,
l_quantity DECIMAL(12,2),
l_extendedprice DECIMAL(12,2),
l_discount DECIMAL(12,2),
l_tax DECIMAL(12,2),
l_returnflag CHAR(1),
l_linestatus CHAR(1),
l_shipdate DATE,
l_commitdate DATE,
l_receiptdate DATE,
l_shipinstruct CHAR(25),
l_shipmode CHAR(10),
l_comment VARCHAR(44))
PARTITION BY RANGE(l_shipdate)
(STARTING '1/1/1992' ENDING '12/31/1993' EVERY 1 MONTH);
这将创建 24 个范围,即对 1992-1993 的每个月创建一个范围。尝试插入 l_shipdate 超出该范围的行将导致错误。
示例 2:将上一示例与以下 Informix 语法作比较:
create table orders
(
l_orderkey decimal(10,0) not null,
l_partkey integer,
l_suppkey integer,
l_linenumber integer,
l_quantity decimal(12,2),
l_extendedprice decimal(12,2),
l_discount decimal(12,2),
l_tax decimal(12,2),
l_returnflag char(1),
l_linestatus char(1),
l_shipdate date,
l_commitdate date,
l_receiptdate date,
l_shipinstruct char(25),
l_shipmode char(10),
l_comment varchar(44)
) fragment by expression
l_shipdate < '1992-02-01' in ldbs1,
l_shipdate >= '1992-02-01' and l_shipdate < '1992-03-01' in ldbs2,
l_shipdate >= '1992-03-01' and l_shipdate < '1992-04-01' in ldbs3,
l_shipdate >= '1992-04-01' and l_shipdate < '1992-05-01' in ldbs4,
l_shipdate >= '1992-05-01' and l_shipdate < '1992-06-01' in ldbs5,
l_shipdate >= '1992-06-01' and l_shipdate < '1992-07-01' in ldbs6,
l_shipdate >= '1992-07-01' and l_shipdate < '1992-08-01' in ldbs7,
l_shipdate >= '1992-08-01' and l_shipdate < '1992-09-01' in ldbs8,
l_shipdate >= '1992-09-01' and l_shipdate < '1992-10-01' in ldbs9,
l_shipdate >= '1992-10-01' and l_shipdate < '1992-11-01' in ldbs10,
l_shipdate >= '1992-11-01' and l_shipdate < '1992-12-01' in ldbs11,
l_shipdate >= '1992-12-01' and l_shipdate < '1993-01-01' in ldbs12,
l_shipdate >= '1993-01-01' and l_shipdate < '1993-02-01' in ldbs13,
l_shipdate >= '1993-02-01' and l_shipdate < '1993-03-01' in ldbs14,
l_shipdate >= '1993-03-01' and l_shipdate < '1993-04-01' in ldbs15,
l_shipdate >= '1993-04-01' and l_shipdate < '1993-05-01' in ldbs16,
l_shipdate >= '1993-05-01' and l_shipdate < '1993-06-01' in ldbs17,
l_shipdate >= '1993-06-01' and l_shipdate < '1993-07-01' in ldbs18,
l_shipdate >= '1993-07-01' and l_shipdate < '1993-08-01' in ldbs19,
l_shipdate >= '1993-08-01' and l_shipdate < '1993-09-01' in ldbs20,
l_shipdate >= '1993-09-01' and l_shipdate < '1993-10-01' in ldbs21,
l_shipdate >= '1993-10-01' and l_shipdate < '1993-11-01' in ldbs22,
l_shipdate >= '1993-11-01' and l_shipdate < '1993-12-01' in ldbs23,
l_shipdate >= '1993-12-01' and l_shipdate < '1994-01-01' in ldbs24,
l_shipdate >= '1994-01-01' in ldbs25;
注意,Informix 语法提供了上下不封顶的范围以捕获预期范围外的日期。通过添加使用 MINVALUE 和 MAXVALUE 的范围,可以将 DB2 语法修改为与 Informix 语法匹配。
示例 3:以下示例将示例 1 修改为与 Informix 语法匹配:
CREATE TABLE orders
(
l_orderkey DECIMAL(10,0) NOT NULL,
l_partkey INTEGER,
l_suppkey INTEGER,
l_linenumber INTEGER,
l_quantity DECIMAL(12,2),
l_extendedprice DECIMAL(12,2),
l_discount DECIMAL(12,2),
l_tax DECIMAL(12,2),
l_returnflag CHAR(1),
l_linestatus CHAR(1),
l_shipdate DATE,
l_commitdate DATE,
l_receiptdate DATE,
l_shipinstruct CHAR(25),
l_shipmode CHAR(10),
l_comment VARCHAR(44)
) PARTITION BY RANGE(l_shipdate)
(STARTING MINVALUE,
STARTING '1/1/1992' ENDING '12/31/1993' EVERY 1 MONTH,
ENDING MAXVALUE);
这种技术允许将任何日期插入到表中。
使用生成列按表达式进行分区
虽然 DB2 数据库并不直接支持按表达式进行分区,但支持按生成列进行分区,因此有可能获得相同的结果。
在决定是否使用此方法前,请考虑下列用法准则:
- 生成列是真实的列,它占用物理磁盘空间。使用生成列的表会略微变大。
- 对于在分区表进行分区时所基于的列,不能改变其生成列表达式。尝试执行此操作将产生消息 SQL0190。如果按下一节描述的方式将新数据分区添加到使用生成列的表中,通常要求改变定义生成列的表达式。目前,不支持改变定义生成列的表达式。
- 当表使用生成列时,对于何时可以应用数据分区消除是有限制的。
示例
示例 1:以下示例使用 Informix 语法,在这种情况下适合使用生成列。在本示例中,进行分区时所基于的列存放了加拿大的省和地域。由于省列表不大可能更改,因此生成列表达式也不大可能更改。
CREATE TABLE customer (
cust_id INT,
cust_prov CHAR(2))
FRAGMENT BY EXPRESSION
cust_prov = "AB" IN dbspace_ab
cust_prov = "BC" IN dbspace_bc
cust_prov = "MB" IN dbspace_mb
...
cust_prov = "YT" IN dbspace_yt
REMAINDER IN dbspace_remainder;
示例 2:在此示例中,使用生成列对 DB2 表进行分区:
CREATE TABLE customer (
cust_id INT,
cust_prov CHAR(2),
cust_prov_gen GENERATED ALWAYS AS (CASE
WHEN cust_prov = 'AB' THEN 1
WHEN cust_prov = 'BC' THEN 2
WHEN cust_prov = 'MB' THEN 3
...
WHEN cust_prov = 'YT' THEN 13
ELSE 14 END))
IN tbspace_ab, tbspace_bc, tbspace_mb, .... tbspace_remainder
PARTITION BY RANGE (cust_prov_gen)
(STARTING 1 ENDING 14 EVERY 1);
这里,CASE 语句中的表达式与 FRAGMENT BY EXPRESSION 子句中的相应表达式匹配。CASE 语句将每个原始表达式映射到一个数字,该数字存储在生成列(在本示例中是 cust_prov_gen)中。此列是存储在磁盘上的真实列,因此,表占用的空间量会比 DB2® 通过表达式直接支持的分区所必需的空间量略多。本示例使用短语法格式。因此,必须在 CREATE TABLE 语句的 IN 子句中列示用来放置数据分区的表空间。如果使用长语法格式,则每个数据分区都需要不同的 IN 子句。