以下的文章主要是阐述DB2 V9.7 本地分区索引的正确创建过程,我们大家都知道一个分区表可以同时存在分区索引与非分区索引 。如果想创建分区索引,那个每个索引分区将都包含单个数据分区的索引条目,索引叶子节点中的 RID 也将只指向单个数据分区 。
在我们使用 Alter table 语句的 Attach Partition 子句将数据 Roll in 或者 Roll Out 分区表时,分区索引将特别有用 。如果使用非分区索引,那么必须先发出 Set Integrity 语句,新添加的分区中的数据才能进入联机状态 。这个过程可能非常消耗时间,并可能消耗大量日志空间 。当使用分区索引时这些开销将会被消除 。
分区索引的每个分区均采用 B 树结构存储,由于分区后一个大型 B 树被划分为若干小型 B 树,树的层数将会减少,这会提高数据的插入、更新、删除以及扫描的性能 。同时我们执行查询时,DB2 将会采用分区消除优化方法提高扫描性能和并行性 。分区消除技术帮助优化器先过滤了不需要的索引分区,只需要扫描相应的分区就能完成查询,这比扫描非分区的索引更为高效 。
清单 1. 创建示例分区表与索引
- CREATE TABLE t1 ( l_orderkey INTEGER, l_partkey INTEGER, l_suppkey INTEGER,
- l_shipdate date, padding1 char(30) )
- PARTITION BY RANGE(l_shipdate)
- (
- partition quarter01 STARTING 2008-01-01 ENDING 2008-03-31in DMS_D1,
- partition quarter02 STARTING 2008-04-01 ENDING 2008-06-30in DMS_D2,
- partition quarter03 STARTING 2008-07-01 ENDING 2008-09-30 in DMS_D3,
- partition quarter04 STARTING 2008-10-01 ENDING 2008-12-31 in DMS_D4
- );
- Create index idx_t1_l_orderkey on t1(l_orderkey) NOT partitioned ;
- Create index idx_t1_l_partkey on t1(l_partkey) partitioned;
上面代码中,我们创建了一个拥有四个分区的范围分区表,同时创建了两个索引 。索引 index idx_t1_l_orderkey 是非分区索引,idx_t1_l_partkey 是分区索引 。
我们下面查看一下上面代码执行后数据字典关于表 T1 以及它的索引的描述 。系统视图 syscat.datapartitions 中包含了分区表的分区信息以及相关统计信息,系统视图 syscat.indexpartitions 中则包含了分区索引的分区信息和相关统计信息 。
清单 2. 分区表的数据分区信息
- db2 "select substr(TABNAME ,1,10) t_name,substr(DATAPARTITIONNAME ,1,10) part_name,
- DATAPARTITIONID ,substr(LOWVALUE,1,12) low_value,substr(HIGHVALUE,1,12) high_value
- from syscat.datapartitions where tabname=T1"
- T_NAME PART_NAME DATAPARTITIONID TBSPACEID LOW_VALUE HIGH_VALUE ----------
- T1 QUARTER01 0 8 2008-01-01 2008-03-31
- T1 QUARTER02 1 9 2008-04-01 2008-06-30
- T1 QUARTER03 2 10 2008-07-01 2008-09-30
- T1 QUARTER04 3 11 2008-10-01 2008-12-31
清单 2 中代码执行查询,从系统视图 syscat.datapartitions 中获取关于数据分区的信息 。查询结果显示,表 T1 具有四个分区,名称与我们创建时相同,ID 依次为 0、1、2、3,数据分布在表空间 DMS_D1(ID 为 8)、DMS_D2(ID 为 9)、DMS_D2(ID 为 10)、DMS_D3(ID 为 11)上 。本例中的表空间信息如下:
清单 3. 表空间信息
- db2 "select substr(TBSPACE,1,18) tablespace_name,TBSPACEID ,TBSPACETYPE
- from syscat.tablespaces"
- TABLESPACE_NAME TBSPACEID TBSPACETYPE
- SYSCATSPACE 0 D TEMPSPACE1 1 S USERSPACE1 2 D
- IBMDB2SAMPLEREL 3 D IBMDB2SAMPLEXML 4 D SYSTOOLSPACE 5 D
- SYSTOOLSTMPSPACE 6 S TBS_TEST 7 D
- DMS_D1 8 D DMS_D2 9 D DMS_D3 10 D DMS_D4 11 D DMS_I1 12 D
-
清单 4. 索引基本信息
- db2 "select substr(tabname,1,10) tab_name, substr(INDNAME,1,18) inx_name,TBSPACEID
- from syscat.indexes where tabname=T1"
- TAB_NAME INX_NAME TBSPACEIDT1 IDX_T1_L_ORDERKEY
- 8
- T1 IDX_T1_L_PARTKEY 65530
我们看到非分区索引 IDX_T1_L_ORDERKEY 数据存放在表空间 DMS_D1 上(ID 为 8),这意味着在创建索引未明确指定表空间时,DB2 将使用第一个数据分区所在的表空间存放非分区索引 。而索引 IDX_T1_L_PARTKEY 所在的表空间 ID 为 65530,我们通过表空间信息部分看到我们的数据库中没有 ID 为 65530 表空间 。
由于分区索引的存储特性是和数据分区关联的,一个索引将分布在多个表空间中,因此 DB2 用了 65530 特殊值表示索引的表空间,并不表示这个 ID 对应的表空间存在 。
清单 5. 索引分区信息
- db2 "select substr(INDNAME,1,18) idx_name,DATAPARTITIONID from syscat.indexpartitions"
- IDX_NAME DATAPARTITIONID
- IDX_T1_L_PARTKEY 0
- IDX_T1_L_PARTKEY 1
- IDX_T1_L_PARTKEY 2
- IDX_T1_L_PARTKEY 3
我们看到索引 IDX_T1_L_PARTKEY 被分为 4 个区,存放索引的表空间与数据分区的表空间相同,如索引 IDX_T1_L_PARTKEY 第一个分区只引用数据分区 0(QUARTER01 分区)的行,数据保存在 DMS_D1 中 。请注意索在创建分区索引时,不能直接为其指定用于存储索引分区的表空间,其表空间由创建表时为数据分区指定的表空间确定 。
默认情况下,分区的缺省存放位置与它所引用的数据分区的位置相同 。
清单 6. 为索引指定表空间
- CREATE TABLE t1 (columns) in ts1 INDEX IN ts2 1
- PARTITION BY RANGE (column expression) (PARTITION PART0 STARTING
- FROM constant ENDING constant IN ts3,
- PARTITION PART1 STARTING FROM constant ENDING constant INDEX IN ts5,
- PARTITION PART2 STARTING FROM constant ENDING constant INDEX IN ts4,
- PARTITION PART3 STARTING FROM constant ENDING constant INDEX IN ts4,
- PARTITION PART4 STARTING FROM constant ENDING constant)
- CREATE INDEX x1 ON t1 (...) NOT PARTITIONED;
- CREATE INDEX x2 ON t1 (...) PARTITIONED;
- CREATE INDEX x3 ON t1 (...) PARTITIONED;
上面的示例中,非分区索引 X1 存储在表空间 TS2 上,这是由于在创建表 T1 的为所有非分区索引指定了缺省表空间 TS2 。
分区索引 X2 和 X3 的数据分区 0 对应的索引分区存储在表空间 ts3 上,这是因为索引分区的缺省位置与其所引用的数据分区相同 。数据分区 1、2 对应的索引分区存储在表空间 ts4 上,这是因为这两个数据分区明确指示了存储索引的表空间 。数据分区 4 对应的索引分区存储存储在 ts1 上,这是因为我们没有给数据分区 4 指定存储表空间,其数据默认存储表空间为 ts1 。
在 DB2 V9.7 以后,用户创建的索引默认都是分区索引 。创建非唯一分区索引时将会 DB2 将会自动使用分区键进行分区 。创建唯一分区索引时,索引列中必须包含用于分区的所有列,否则 DB2 将返回 SQL20303N 错误表示索引创建失败 。