表分區功能是一種數據組織方案,即,表數據根據一個或多個表列中的值分布到多個存儲對象(稱為數據分區或范圍)中。每個數據分區都是單獨存儲的。這 些存儲對象可以在不同的表空間中,也可以在相同表空間中。按照 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 子句。