1.分区的概念及方法
分区是指将表、索引等数据库对象划分为较小的可管理片段的技术,每一个片段称为分区子表或分区索引。一个表被分区后,对表的查询操作可以局限于某个分区进行,而不是整个表,这样可以大大提高查询速度。
达梦数据库 DM 支持对表进行水平分区。对于水平分区,提供以下分区方式:
1. 范围(range)水平分区:对表中的某些列上值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上;管理分区表和分区索引
2. 哈希(hash)水平分区:通过指定分区编号来均匀分布数据的一种分区类型,通过在 I/O 设备上进行散列分区,使得这些分区大小基本一致;
3. 列表(list)水平分区:通过指定表中的某个列的离散值集,来确定应当存储在一起的数据。例如,可以对表上的 status列的值在('A','H','O')放在一个分区,值在('B','I','P')放在另一个分区,以此类推;
4. 多级分区表:按上述三种分区方法进行任意组合,将表进行多次分区,称为多级分区表。
2.创建范围分区
范围分区是按照某个列或几个列的值的范围来创建分区,当用户向表中写入数据时,数据库服务器将按照这些列上的值进行判断,将数据写入相应的分区中。在创建范围分区时,首先要指定分区列,即按照哪些列进行分区,然后为每个分区指定数据范围。范围分区支持 MAXVALUE 范围值的使用,MAXVALUE相当于一个比任何值都大的值。范围分区非常适用于数据按时间范围组织的表,不同的时间段的数据属于不同的分区。
例如,以下语句创建一个范围分区表 callinfo,用来记录用户的 2010 年的电话通讯信息,包括主叫号码、被叫号码、通话时间和时长,并且根据季度进行分区。
CREATE TABLE callinfo(
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
)
PARTITION BY RANGE(time)(
PARTITION p1 VALUES LESS THAN ('2010-04-01'),
PARTITION p2 VALUES LESS THAN ('2010-07-01'),
PARTITION p3 VALUES LESS THAN ('2010-10-01'),
PARTITION p4 VALUES EQU OR LESS THAN ('2010-12-31') --'2010-12-31'也可替换 为 MAXVALUE );
值得注意的是,MAXVALUE 之间无法比较大小
3.创建list分区
范围分区是按照某个列上的数据范围进行分区的,如果某个列上的数据无法通过划分范围的方法进行分区,并且该列上的数据是相对固定的一些值,可以考虑使用 LIST 分区。一般来说,对于数字型或者日期型的数据,适合采用范围分区的方法;而对于字符型数据,取值比较固定的,则适合于采用 LIST 分区的方法。
例如,创建一个产品销售记录表 sales,记录产品的销量情况。由于产品只在几个固定的城市销售,所以可以按照销售城市对该表进行分区。
CREATE TABLE sales(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY LIST(city)(
PARTITION p1 VALUES ('北京', '天津'),
PARTITION p2 VALUES ('上海', '南京', '杭州'),
PARTITION p3 VALUES ('武汉', '长沙'),
PARTITION p4 VALUES ('广州', '深圳')
);
在创建 LIST 分区时,通过“PARTITION BY LIST”子句指定对表进行 LIST 分区,然后在每个分区中分区列的取值通过 VALUES 子句指定。当用户向表插入数据时,只要分区列的数据与 VALUES 子句指定的数据之一相等,该行数据便会写入相应的分区子表中。注意的是,LIST 分区的分区键必须唯一。
4.创建hash分区
在很多情况下,用户无法预测某个列上的数据变化范围,因而无法实现创建固定数量的范围分区或 LIST 分区。
在这种情况下,DM哈希分区提供了一种在指定数量的分区中均等地划分数据的方法,基于分区键的散列值将行映射到分区中。当用户向表中写入数据时,数据库服务器将根据一个哈希函数对数据进行计算,把数据均匀地分布在各个分区中。在哈希分区中,用户无法预测数据将被写入哪个分区中。
例如,创建一个产品销售记录表 sales,记录产品的销量情况。由于产品只在几个固定的城市销售,所以可以按照销售城市对该表进行分区。
CREATE TABLE sales(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY LIST(city)(
PARTITION p1 VALUES ('北京', '天津'),
PARTITION p2 VALUES ('上海', '南京', '杭州'),
PARTITION p3 VALUES ('武汉', '长沙'),
PARTITION p4 VALUES ('广州', '深圳')
);
PARTITIONS 后的数字表示哈希分区的分区数,STORE IN 子句中指定了哈希分区依次使用的表空间。使用这种方式建立的哈希分区表分区名是匿名的,DM 统一使用DMHASHPART+分区号(从 0 开始)作为分区名。例如,需要查询 sales 第一个分区的数据,可执行以下语句:
SELECT * FROM sales02 PARTITION (dmhashpart0);
5.创建多级分区表
在很多情况下,经过一次分区并不能精确地对数据进分类,这时需要多级分区表。例如,创建一个产品销售记录表 sales,记录产品的销量情况。由于产品需要按地点和销售时间进行统计,则可以对该表进行 LIST-RANGE 分区。
DROP TABLE SALES;
CREATE TABLE SALES(
SALES_ID INT,
SALEMAN CHAR(20),
SALEDATE DATETIME,
CITY CHAR(10)
)
PARTITION BY LIST(CITY)
SUBPARTITION BY RANGE(SALEDATE) SUBPARTITION TEMPLATE(
SUBPARTITION P11 VALUES LESS THAN ('2012-04-01'),
SUBPARTITION P12 VALUES LESS THAN ('2012-07-01'),
SUBPARTITION P13 VALUES LESS THAN ('2012-10-01'),
SUBPARTITION P14 VALUES EQU OR LESS THAN (MAXVALUE)) (
PARTITION P1 VALUES ('北京', '天津')
(
SUBPARTITION P11_1 VALUES LESS THAN ('2012-10-01'),
SUBPARTITION P11_2 VALUES EQU OR LESS THAN (MAXVALUE)
),
PARTITION P2 VALUES ('上海', '南京', '杭州'),
PARTITION P3 VALUES (DEFAULT)
);
在创建多级分区表时,指定了子分区模板,同时子分区 P1 自定义了子分区描述 P11_1和 P11_2。P1 有两个子分区 P11_1 和 P11_2。而子分区 P2 和 P3 有四个子分区 P11、P12、P13 和 P14。
6.在水平分区表建立索引
DM 支持对水平分区表建立普通索引、唯一索引、聚集索引、函数索引、位图索引和空间索引。
创建水平分区表时,若表的 PRIMARY KEY未包含所有分区列,系统会自动创建全局索引,否则自动创建局部索引。创建全局索引时,在水平分区表的主表创建全局索引,每个分区子表的数据都被索引在同一个 B树中,并在每个子表创建全局本地索引,与主表共用一个 B 树。
例如,下面的语句在创建水平分区表 test 时会自动创建一个全局索引。
CREATE TABLE test(c1 INT, c2 INT PRIMARY KEY) PARTITION BY HASH(c1)
PARTITIONS 2;
当使用创建索引语句在水平分区表上创建索引时,若指定 GLOBAL 关键字,创建全局索引,否则创建为局部索引。
在水平分区表上创建唯一索引时,全局唯一索引总是可以创建的,若要创建非全局唯一索引,则要求索引键包含所有的分区键。这是因为对于局部索引,每一个分区子表都会建立一个索引分区,负责索引分区子表的数据。由于每个索引分区只负责索引本分区上的数据,其他分区上的数据无法维护,只有当分区键都包含在索引键中时,才能对分区主表保证索引键唯一。
例如,在 sales 表上的 saledate 列上建立局部索引,在 city 列上建立非全局唯一索引。
CREATE INDEX ind_sales_saldate ON sales(saledate);
CREATE UNIQUE INDEX ind_sales_city ON sales(city);
另外,只能在水平分区表上创建局部聚集索引,不能创建全局聚集索引;不能在水平分区表上创建局部唯一函数索引;HUGE 水平分区表不支持全局索引
7.维护水平分区表
创建水平分区表后,DM 提供了对分区表的修改,功能包括:
1. 增加分区:建立水平分区表后,可根据实际需要新增一个分区;
2. 删除分区:建立水平分区表后,可根据实际需要删除一个分区;
3. 合并分区:将相邻的两个范围分区合并为一个分区。合并分区通过指定两个分区名
进行,将相邻的两个分区的数据进行合并,构建新的大分区。只能在范围和 LIST
分区上进行合并分区;
4. 拆分分区:将某一个范围分区拆分为相邻的两个分区。拆分分区时指定的常量表达
式值必须是原范围分区的有效范围值。只能在范围和 LIST 分区上进行拆分分区;
5. 交换分区:将分区数据跟普通表数据交换功能,普通表必须跟分区表同构(拥有相
同的列和索引)。不支持含有加密列的分区表交换分区。
在 DM 中,由于局部索引反映基础表的结构,因此当对表的分区和子分区进行修改操作
时,会自动地对局部索引进行相应的修改。
7.1增加分区
DM 支持用 ALTER TABLE ADD PARTITION 语句将新分区增加到最后一个现存分区的后面。
例如,范围分区表 callinfo 现需要记录用户的 2011 年的第一季度的通讯信息,那么,需要为 2011 年第一季度增加一个分区,并将其存储在表空间 ts5 中。
ALTER TABLE callinfo ADD PARTITION p5 VALUES LESS THAN ('2011-4-1') STORAGE (ON ts5);
对于范围分区,增加分区必须在最后一个分区范围值的后面添加,要想在表的开始范围或中间增加分区,应使用 SPLIT PARTITION 语句。
对于 LIST 分区,增加分区包含的离散值不能已存在于某个分区中。
例如,为 LIST 分 区表 sales 添加一个分区管理拉萨和呼和浩特的销售情况。
ALTER TABLE sales ADD PARTITION p5 VALUES ('拉萨', '呼和浩特') STORAGE (ON ts5);
可以对范围分区和 LIST 分区增加分区,存储选项 HASHPARTMAP 为 1 的 HASH 分区表也支持增加分区。增加分区不会影响分区索引,因为分区索引只是局部索引,新增分区仅是新增分区子表,并更新分区主表的分区信息,其他分区并不发生改变。
7.2删除分区
DM 支持用 ALTER TABLE DROP PARTITION 语句将分区删除。
例如,范围分区表callinfo 现需要删除记录用户的 2011 年的第一季度的通讯信息,那么,只需删除callinfo 的分区 p1 即可。
ALTER TABLE callinfo DROP PARTITION p1;
只能对范围分区和 LIST 分区进行删除分区,哈希分区不支持删除分区。跟增加分区一样,删除分区不会影响分区索引,因为分区索引只是局部索引,删除分区仅是删除分区子表,并更新分区主表的分区信息,其他分区并不发生改变。
7.3交换分区
假设上文提到的 callinfo 表是用于维护最近 12 个月的用户通话信息,超过 12 个月的订单需要迁移到该季度的通话信息历史表中,并且每一个季度都有一个相应的历史表。如果没有使用水平分区,需要较多的删除和插入操作,并产生大量的 redo 和 undo 日志。如果使用分区表,如上文提到的 callinfo,只需使用交换分区即可完成以上功能。
例如,2011 年第二季度已到了,需删除 2010 年第二季度的通话记录,因此,可通过以下脚本来实现:
CREATE TABLE callinfo_2011Q2(
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
);
--交换分区
ALTER TABLE callinfo EXCHANGE PARTITION p2 WITH TABLE callinfo_2011Q2;
--删除原分区
ALTER TABLE callinfo DROP PARTITION p2;
--新增分区,记录 2011 年第二季度通话记录
ALTER TABLE callinfo
ADD PARTITION p6 VALUES LESS THAN ('2011-7-1') STORAGE (ON ts2);
通过交换分区实现分区 p2 和新建表 callinfo_2011Q2 的 数 据 交 换 , 表callinfo_2011Q2 将得到 2010 年第二季度的通话记录,而分区 p2 数据将被清空。交换分区采用数据字典信息交换的技术,几乎不涉及 IO 操作,因此效率非常高。仅范围分区和 LIST 分区支持交换分区,哈希分区表不支持。并且分区交换要求分区表跟交换表具有相同的结构(相同的表类型、相同的 BRANCH 选项、相同的列结构、相同的索引、相同的分布方式),分区交换但并不会校验数据,如交换表的数据是否符合分区范围等,即不能保证分区交换后的分区上的数据符合分区范围。进行交换的两张表,如果包含加密列,对应的加密列要求加密信息完全一致。
7.4合并分区
要想将两个范围分区的内容融合到一个分区,就要使用 ALTER TABLE MERGE PARTITION 语句。如果分区的数据很少,或相对其他分区某些分区的数据量较少,导致 I/O不均衡,就可以考虑使用合并分区。
例如,可将 callinfo 的 2010 第 3 季度和第 4 季度合并成一个分区:ALTER TABLE callinfo MERGE PARTITIONS p3, p4 into partition p3_4;仅范围分区表和 LIST 分区表支持合并分区。其中,合并的 RANGE 分区必须是范围相邻的两分区。多级分区表进行 MERGE 合并的注意事项:
1. 仅支持一级子表类型为 RANGE、LIST;
2. 合并多级分区表中的一级子表时,该一级子表下的二级及以上层次子表按照级别分别由系统自动合并为一个子表,子表名称为系统内部设置。RANGE类型范围值为MAXVALUE;LIST 类型范围值为 DEFAULT;
3. 不允许自定义二级及以上层次子表;
4. 不允许直接合并二级及以上层次子表。合并分区会导致数据的重组和分区索引的重建,因此,合并分区可能会比较耗时,所需时间取决于分区数据量的大小。
7.5 拆分分区
ALTER TABLE 语句的 SPLIT PARTITION 子句被用于将一分区中的内容重新划分成两个新的分区。当一个分区变得太大以至于要用很长时间才能完成备份、恢复或维护操作时,就应考虑做分割分区的工作,还可以用 SPLIT PARTITION 子句来重新划分 I/O 负载。
例如,将合并后的 p3_4 拆分为原两分区 p3 和 p4,分别记录 2010 年第三和第四季度的通话记录。
ALTER TABLE callinfo SPLIT PARTITION p3_4 AT ('2010-9-30') INTO (PARTITION p3, PARTITION p4);
仅范围分区表和 LIST 分区表支持拆分分区。拆分分区另一个重要用途是作为新增分区的补充。通过拆分分区,可以对范围分区表的开始或中间范围添加分区。多级分区表进行拆分 SPLIT 注意事项:
1. 仅支持一级子表类型为 RANGE、LIST;
2. 支持 SPLIT 为 2 个或多个子表;
3. 不允许自定义二级及以上层次子表;
4. SPLIT 产生的新分区二级及以上层次子表结构与被分隔子表保持一致,名称由系统内部定义。
拆分分区会导致数据的重组和分区索引的重建,因此,拆分分区可能会比较耗时,所需时间取决于分区数据量的大小。
8.水平分区表的限制
DM 水平分区表有如下限制条件:
1. 分区列类型必须是数值型、字符型或日期型,不支持 BLOB、CLOB、IMAGE、TEXT、LONGVARCHAR、BIT、BINARY、VARBINARY、LONGVARBINARY、时间间隔类型和用户自定义类型为分区列;
2. 范围分区和哈希分区的分区键可以多个,最多不超过 16 列;LIST 分区的分区键必须唯一;
3. 水平分区表指定主键和唯一约束时,分区键必须都包含在主键和唯一约束中;
4. 水平分区表不支持临时表;
5. 不能在水平分区表上建立自引用约束;
6. 普通环境中,水平分区表的各级分区数的总和上限是 65535;MPP 环境下,水平分区表的各级分区总数上限取决于 INI 参数 MAX_EP_SITES,上限为 2 ^( 16 -log2MAX_EP_SITES)。比如:当 MAX_EP_SITES 为默认值 64 时,分区总数上限为 1024;
7. 不允许对分区子表执行任何 DDL 操作;
8. 哈希分区支持重命名、增加/删除约束、设置触发器是否启用的修改操作;
9. 范围分区支持分区合并、拆分、增加、删除、交换、重命名、增加/删除约束、设置触发器是否生效操作;
10. LIST 分区支持分区合并、拆分、增加、删除、交换、重命名、增加/删除约束、设置触发器是否生效操作;
11. LIST 分区范围值不能为 NULL;
12. LIST分区子表范围值个数与数据页大小和相关系统表列长度相关,存在以下限制:
1) 4K 页,单个子表最多支持 120 个范围值;
2) 8K 页,单个子表最多支持 254 个范围值;
3) 16K\32K 页,单个子表最多支持 270 个范围值;
13. 对范围分区增加分区值必须是递增的,即只能在最后一个分区后添加分区。LIST分区增加分区值不能存在于其他已存在分区;
14. 当分区数仅剩一个时,不允许删除分区;
15. 仅能对相邻的范围分区进行合并,合并后的分区名可为高分区名或新分区名;
16. 拆分分区的分区值必须在原分区范围中,并且分区名不能跟已有分区名相同;
17. 与分区进行分区交换的普通表,必须与分区表拥有相同的列及索引,但交换分区并不会对数据进行校验,即交换后的数据并不能保证数据完整性,如 CHECK 约束;分区表与普通表创建的索引顺序要求一致;
18. 不能对水平分区表建立全局聚集索引、局部唯一函数索引或全文索引;
19. 不能对分区子表单独建立索引;
20. 在未指定 ENABLE ROW MOVEMENT 的分区表上执行更新分区键,不允许更新后数据发生跨分区的移动,即不能有行迁移;
21. 不能在分区语句的 STORAGE 子句中指定 BRANCH 选项;
22. 不允许引用水平分区子表作为外键约束;
23. 多级分区表最多支持八层;
24. 多级分区表支持下列修改表操作:新增分区、新增列、删除列、删除表级约束、修改表名、设置与删除列的默认值、设置列 NULL 属性、设置列可见性、设置行迁移属性、启用超长记录、with delta、新增子分区、删除子分区、修改二级分区模板信息;
25. 水平分区表支持的列修改操作除了多级分区表支持的操作外,还支持:设置触发器生效/失效、修改列名、修改列属性、增加表级主键约束、删除分区、SPLIT/MERGE分区和交换分区;
26. 水平分区表中包含大字段、自定义字段列,则定义时指定 ENABLE ROW MOVEMENT 参数无效,即不允许更新后数据发生跨分区的移动;
27. 间隔分区表的限制说明:
1) 仅支持一级范围分区创建间隔分区;
2) 只能有一个分区列,且分区列类型为日期或数值;
3) 对间隔分区进行 SPLIT,只能在间隔范围内进行操作;
4) 被 SPLIT/MERGE 的分区,其左侧分区不再进行自动创建;
5) 不相邻的间隔的分区,不能 MERGE;
6) 表定义不能包含 MAXVALUE 分区;
7) 不允许新增分区;
8) 不能删除起始间隔分区;
9) 间隔分区表定义语句显示到起始间隔分区为止;
10)自动生成的间隔分区,均不包含边界值;
11)间隔表达式只能为常量 或 日期间隔函数。日 期间隔函数为:NUMTOYMINTERVAL、NUMTODSINTERVAL;数值常量可以为整型、DEC 类 型;
12)MPP 下不支持间隔分区表。
社区地址:https://eco.dameng.com