分区
分区,及多级分区。分区与分布:
1.分区,按照字段逻辑进行逻辑划分的区域,比如,时间按天,按月等等
2.分布,按照字段进行物理分区,会分散到每个segment
分布式为了并行查询效率,充分利用每个segment节点的资源,分区是为了减少查询时的数据扫描,对大表维护更加方便。
本文讲来都是声明式分区。声明式分区是内置的表分区功能,其在性能与易用性方面都优于继承方式实现的表分区,推荐优先采用声明式分区。
总章
声明式分区支持范围分区、列表分区。
分区裁剪的开关,检测效果,通过explain 查询语句查看执行计划,确定效果。
SET constraint_exclusion = off; --关闭
SET constraint_exclusion = partition;
优缺点
利用上分区裁剪,避免全表扫描。因为数据一般都会有热点数据、历史数据。历史数据访问量不大,故分区裁剪时,能避免全表扫描。
不同的分区,能指定存放到不同的位置。
分区
列表分区
create table "public".demo_part1 (
id1 int,
id2 VARCHAR(10)
)
DISTRIBUTED by(id1)
PARTITION by list(id2)(
partition p1 values ('1','2'),
partition p2 values ('3','0'),
default partition pdefault
)
;
日期/时间–范围分区
方式1
create table "public".demo_part2(
id1 integer,
id2 varchar( 10),
id3 date,
id4 integer
)
distributed by (id1)
--从1号到31号每一天为一个子分区表
partition by range(id4)(
START (1) END (31) every(1),
default partition none
);
方式2
create table "public".demo_part2(
id1 integer,
id2 varchar( 10),
id3 date,
id4 integer
)
distributed by (id1)
-- 指定时同区间作为子分区
-- 分区的values必须是与分区表分区键摸型对应的值,如无对应分区,数据插入时会出错。
-- 且不需要一次性将所有分区写入,有分区表存储过程可自动增加相应分区
partition by range(id3)(
partition p1 START ('2018-08-20') END ( '2018-09-20 '),
partition p2 START ('2018-09-21') END ( '2018-09-30'),
default partition pn_default
);
create table "public".demo_part2(
id1 integer,
id2 varchar( 10),
id3 date,
id4 integer
)
distributed by (id1)
--从18年到19年每七天为一个子分区表
partition by range( id3 ) (
START ('2018-01-01') INCLUSIVE
END ('2019-01-01 ') EXCLUSIVE
EVERY (INTERVAL '7 day' )
);
多级分区
--首先以period字段为表p建立一级范国分区,指定从18年到19年每一个月为一个子分区表
--子分区表以region字段为一级分区建立二级子分区
create table "public".demo_part3(
id int,
period date,
sales decimal( 9,6),
Region varchar (500)
)
distributed by (id)
partition by range (period)
subpartition by list (region)
subpartition template(
subpartition usa values ( 'usa'),
subpartition asia values ('asia'),
subpartition europe values ('europe' ),
default subpartition other
)
(
start( ' 2018-01-01 ') inclusive
end ( '2019-01-01 ' ) exclusive
every (interval '1 month' ),
default partition other
);
分割分区
改示例演示,如何从一个默认的分区中,分割出新的分区。
一般我喜欢的建表语句如下:
CREATE TABLE public.marked_ship (
id bigint,
ship_id varchar(60),
ship_type varchar(60),
insert_db_date timestamp without time zone,
gmt_create_time timestamp without time zone
)
with (appendonly=true, compresslevel=5, orientation=column, compresstype=zlib)
Distributed by (ship_id)
partition by range (insert_db_date)
(
PARTITION pn START ('2021-06-01 00:00:00'::timestamp without time zone) END ('2023-01-01 00:00:00'::timestamp without time zone) EVERY ('1 day'::interval),
DEFAULT PARTITION pdefault
);
从默认分区中,分隔出3天新的分区。内容如下:
PARTITION pn_20230101 , 不允许再填写时间范围了,因为在前面已经填写过了。
DEFAULT PARTITION 默认写法,不用再写默认分区的名称了。
ALTER TABLE public.marked_ship SPLIT DEFAULT PARTITION START ('2023-01-01 00:00:00'::timestamp without time zone) END ('2023-01-02 00:00:00'::timestamp without time zone) INTO (
PARTITION pn_20230101 ,
DEFAULT PARTITION
) ;
ALTER TABLE public.marked_ship SPLIT DEFAULT PARTITION START ('2023-01-02 00:00:00'::timestamp without time zone) END ('2023-01-03 00:00:00'::timestamp without time zone) INTO (
PARTITION pn_20230102 ,
DEFAULT PARTITION
) ;
ALTER TABLE public.marked_ship SPLIT DEFAULT PARTITION START ('2023-01-03 00:00:00'::timestamp without time zone) END ('2023-01-04 00:00:00'::timestamp without time zone) INTO (
PARTITION pn_20230103 ,
DEFAULT PARTITION
) ;
以上,即每增加一个分区,都要写一次分割语句。当然,完全可以用脚本、模板等批量形成这样的语句。
时间戳分区
以下有默认分区、最小范围分区、最大范围分区。如下:
PARTITION BY range(ins_db_tm)
(
DEFAULT PARTITION defp0 WITH (appendonly='true', compresslevel='5', orientation='column', compresstype=zlib),
PARTITION p20200101 START ('2020-01-01 00:00:00'::timestamp without time zone) END ('2020-01-02 00:00:00'::timestamp without time zone) WITH (appendonly='true', compresslevel='5', orientation='column', compresstype=zlib),
....省略了若干
PARTITION p20221231 START ('2022-12-31 00:00:00'::timestamp without time zone) END ('2023-01-01 00:00:00'::timestamp without time zone) WITH (appendonly='true', compresslevel='5', orientation='column', compresstype=zlib),
PARTITION pmax START ('2023-01-01 00:00:00'::timestamp without time zone) END ('9999-12-31 00:00:00'::timestamp without time zone) WITH (appendonly='true', compresslevel='5', orientation='column', compresstype=zlib),
PARTITION pmin START ('0001-01-01 00:00:00'::timestamp without time zone) END ('2020-01-01 00:00:00'::timestamp without time zone) WITH (appendonly='true', compresslevel='5', orientation='column', compresstype=zlib)
);
需要计算的分区
比如,有订单号,我需要根据订单号的最后1位或多位,来判断,如何写呢?
即,分区的字段,需要参与计算。
按之前我的精力,我可以先存,再进行etl计算。参见其他文件。
字段能计算吗?一般字段计算后,无法直接使用到索引等条件。分区的时候,是不是能计算?