分区

分区,及多级分区。分区与分布:

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计算。参见其他文件。

字段能计算吗?一般字段计算后,无法直接使用到索引等条件。分区的时候,是不是能计算?