南大通用GBase 8a集群支持分区表功能使用样例

GBase 8a数据库集群,从V9版本才支持分区功能,V8不支持分区。分区表是根据一定规则,将数据库中的一张表分解成多个更小的容易管理的部分,从逻辑上看,只有一张表,但底层却是由多个物理分区组成。分区表包括普通分区表和子分区表。

参考

GBase 8a 元数据表介绍,分区information_schema.Partitions
GBase 8a 元数据表介绍
GBase 8a分区表指定特定分区的查询方法
GBase 8a数据库Range分区表null值保存分区位置测试

数据库版本

不同的版本可能功能有变动,如需要了解详情,请咨询数据库厂商当前最新版本的情况。本文也会尽量同步更新。


gbase> select @@version;
+-----------------+
| @@version       |
+-----------------+
| 9.5.2.26.121440 |
+-----------------+
1 row in set (Elapsed: 00:00:00.00)

支持的分区类型

目前常用的分区方法有RANGE分区、LIST分区、KEY分区、HASH分区,在分区的管理上目前支持创建分区、添加分区、删除分区。
RANGE分区表和LIST分区表支持子分区,子分区的分区类型可以为[LINEAR] HASH和[LINEAR] KEY。
information_schema.partitions中可以查到所创建的分区表信息。

RANGE : 一个连续范围
LIST : 一个个的单独指定的值,可以不连续
KEY: 支持各种数据类型,比如字符串,的hash分类方式。
HASH: 针对数字的的hash

分区表支持分区列类型

数值型, 如: int, bigint, smallint, float 等
时间类型: date,datetime, time

支持分区函数

abs(), ceiling(), ceil(), datadiff(), day(), dayofmonth(), dayofweek(),dayofyear(), floor(), hour(), microsecond(), minute(), mod(),month(), quarter(), second(), time_to_sec(), to_days(), to_seconds(),weekday(), year(),yearweek(), +, -, *, /, div, %, extract(),from_days()

分区

range 分区

数字类型的range分区

gbase> create table p1(id int)
partition by range(id)(
  partition p1 values less than (10), 
  partition po values less than MAXVALUE
);
Query OK, 0 rows affected (Elapsed: 00:00:02.29)

日期类型的RANGE分区

create table t_list_1(id int, name varchar(100),birth date)
    partition by range(birth)
   (
        partition p1357_1980 values less than (to_date('1980-01-01','yyyy-mm-dd')),
        partition p1357_2000 values less than (to_date('2000-01-01','yyyy-mm-dd')),
        partition p1357_other values less than MAXVALUE
    );

多列RANGE分区

当前版本尚不支持,但后续可能会实现。

gbase>     create table t_range_multi(id int, name varchar(100),birth date)
    ->     partition by range(id,birth)
    ->    (
    ->         partition p1357_1980 values less than (10,to_date('1980-01-01','yyyy-mm-dd')),
    ->         partition p1357_2000 values less than (20,to_date('2000-01-01','yyyy-mm-dd')),
    ->         partition p1357_other values less than MAXVALUE
    ->     );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your GBase server version for the right syntax to use near 'birth)
   (
        partition p1357_1980 values less than (10,to_date('1980-01-0' at line 2
gbase>

list分区

gbase> create table p2 (id int) 
partition by list(id)(   
  partition a values in (1,3,5,7),
  partition b values in (2,4,6,8) 
);
Query OK, 0 rows affected (Elapsed: 00:00:00.61)

Key分区

如果没指定分区名字,则默认从p0开始,p0,p1,p2...。查询时可以用 partition(p0,p1)这样来指定分区。

int类型的key分区

create table t_key_int(id int, name varchar(100),birth date)
    partition by key(id)
    (
         partition p01,
         partition p02         
    );

gbase> create table t_key_int(id int, name varchar(100),birth date)
    ->     partition by key(id)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
Query OK, 0 rows affected (Elapsed: 00:00:00.16)

varchar类型的key分区

create table t_key_varchar(id int, name varchar(100),birth date)
    partition by key(name)
    (
         partition p01,
         partition p02         
    );
gbase> create table t_key_varchar(id int, name varchar(100),birth date)
    ->     partition by key(name)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
Query OK, 0 rows affected (Elapsed: 00:00:00.17)

date类型的key分区

create table t_key_date(id int, name varchar(100),birth date)
    partition by key(birth)
    (
         partition p01,
         partition p02         
    );

gbase> create table t_key_date(id int, name varchar(100),birth date)
    ->     partition by key(birth)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
Query OK, 0 rows affected (Elapsed: 00:00:00.42)

Hash分区

如果没指定分区名字,则默认从p0开始。查询时可以用 partition(p0,p1)这样来指定分区。

数字类型的hash分区

整数在内部,就是按照数字的mod值进行划分。比如10个节点,数字0保存在第1个分区,数字9保存在第10个分区。

create table t_hash_int(id int, name varchar(100),birth date)
    partition by hash(id)
    (
         partition p01,
         partition p02         
    );
gbase> create table t_hash_int(id int, name varchar(100),birth date)
    ->     partition by hash(id)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
Query OK, 0 rows affected (Elapsed: 00:00:00.17)

其它类型的hash分布不支持

gbase> create table t_hash_varchar(id int, name varchar(100),birth date)
    ->     partition by hash(name)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
ERROR 1702 (HY000): gcluster table error: The PARTITION function returns the wrong type.
gbase> create table t_hash_date(id int, name varchar(100),birth date)
    ->     partition by hash(birth)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
ERROR 1050 (42S01): Table 't_hash_date' already exists
gbase> drop table t_hash_date;
Query OK, 0 rows affected (Elapsed: 00:00:00.04)

gbase> create table t_hash_date(id int, name varchar(100),birth date)
    ->     partition by hash(birth)
    ->     (
    ->          partition p01,
    ->          partition p02
    ->     );
ERROR 1702 (HY000): gcluster table error: The PARTITION function returns the wrong type.
gbase>

PARTITIONS num 批量建立

批量生成一定的分区,不再指定分区名字,适合key和hash分区类型。

gbase> create table t_key_varchar(id int, name varchar(100),birth date)
    ->     partition by key(name)
    ->     PARTITIONS 10;
Query OK, 0 rows affected (Elapsed: 00:00:00.54)

子分区

key和hash不能再有子分区,只允许RANGE/LIST可以拥有子分区,包括hash/key子分区类型。

提示:当前集群版本,还不支持range-list这样的子分区格式,具体当前最新版本支持详情,还请咨询数据库厂商。

语法

 PARTITION BY
 { RANGE(expr)
 | LIST(expr)
 | LINEAR] HASH(expr)
 | [LINEAR] KEY(column_list)}
 [PARTITIONS num]
 
[SUBPARTITION BY
 { [LINEAR] HASH(expr)
 | [LINEAR] KEY(column_list) }
 [SUBPARTITIONS num]
 ]

样例

如下是日期类型的Range分区带hash类型的子分区的例子。

    create table t_list_2(id int, name varchar(100),birth date)
    partition by range(birth)
    subpartition by hash(id)
   (
        partition p1357_1980 values less than (to_date('1980-01-01','yyyy-mm-dd'))(
            subpartition a1980,
            subpartition b1980 
        ),
        partition p1357_2000 values less than (to_date('2000-01-01','yyyy-mm-dd'))(
            subpartition a2000,
            subpartition b2000 
        ),
        partition p1357_other values less than MAXVALUE(
            subpartition aother,
            subpartition bother 
        )
    );

SUBPARTITIONS num 批量建立

对于key和hash的子分区,可以批量建立,不指定名字。

    create table t_range_hash(id int, name varchar(100),birth date)
    partition by range(birth)
    subpartition by hash(id) subpartitions 2
   (
        partition p1357_1980 values less than (to_date('1980-01-01','yyyy-mm-dd')),
        partition p1357_2000 values less than (to_date('2000-01-01','yyyy-mm-dd')),
        partition p1357_other values less than MAXVALUE
    );

增加分区

目前版本只有Range和List分区支持增加分区

gbase> show create table td;
CREATE TABLE "td" (
  "id" int(11) DEFAULT NULL,
  "d" date DEFAULT NULL
) ENGINE=EXPRESS DEFAULT CHARSET=utf8 TABLESPACE='sys_tablespace'
 PARTITION BY RANGE (d)
(PARTITION p_20230307 VALUES LESS THAN (20230308) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS,
 PARTITION p_20230308 VALUES LESS THAN (20230309) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS) 

1 row in set (Elapsed: 00:00:00.01)

gbase> alter table td add partition(partition p_20230309 values less than (20300310));
Query OK, 0 rows affected (Elapsed: 00:00:00.28)
Records: 0  Duplicates: 0  Warnings: 0

gbase> show create table td;

CREATE TABLE "td" (
  "id" int(11) DEFAULT NULL,
  "d" date DEFAULT NULL
) ENGINE=EXPRESS DEFAULT CHARSET=utf8 TABLESPACE='sys_tablespace'
 PARTITION BY RANGE (d)
(PARTITION p_20230307 VALUES LESS THAN (20230308) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS,
 PARTITION p_20230308 VALUES LESS THAN (20230309) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS,
 PARTITION p_20230309 VALUES LESS THAN (20300310) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS) |

1 row in set (Elapsed: 00:00:00.01)

注意,Range分区,如果设定了Max分区,则不能直接增加分区,否则数据会出现重叠。比如

CREATE TABLE "td_max" (
  "d" datetime DEFAULT NULL,
  "id" int(11) DEFAULT NULL
) ENGINE=EXPRESS DEFAULT CHARSET=utf8 TABLESPACE='sys_tablespace'
 PARTITION BY RANGE (d)
(PARTITION p_20230307 VALUES LESS THAN (20230307000000) TABLESPACE = 'sys_tablespace' ENGINE = EXPRESS,
 PARTITION p_max VALUES LESS THAN MAXVALUE 

可以考虑将MAXVALUE分区删除,如果有数据。可以将MAXVALUE分区数据临时迁移到一个表里,然后删除MAXVALUE分区,建好分区后,再把数据迁移过来。

create table tmp as select * frm td_max partition(p_max);
alter table td_max drop partition p_max;
alter table add partition ....
insert into td_max select * from tmp;
drop table tmp;

删除分区

alter table td_max drop partition p_max;