PostgreSQL分区方案测试(数据插入与分区表数量关系)

一 前言

单表数据量太大时,数据库通过建立分区表的方式,从而达到对大表进行拆分,使每个分区的子表数据规模适中,方便数据管理与常规查询分析等,分区表是数据库比较常用的数据管理需求。
当前PostgreSQL 11版本及其社区目前分区方案整理如下:

  • Pg11自带分区表,目前分区类型有list,range,hash三种类型。
  • 社区分区插件pg_pathman,目前分区类型支持range,hash类型。
  • citus为代表的分布式数据节点分区方案,目前支持hash(更常用更通用)与append类型(不是很了解,不怎么常用,使用需谨慎)。
    这些方案都能在不同场景下支持不同的分区方案,本文选择一个方向对这些分区方案进行测试,即:某个表的分区表数量逐渐增多与数据插入性能衰减程度关系

二 测试过程

2.1 基准测试

对某个表不做任何分区,使用pgbench压测,测试插入tps。
建立表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
);
create index shiptrack_id_idx on shiptrack using btree(ship_id);
create index shiptrack_time_idx on shiptrack using btree(pos_time);

测试脚本 test.sql:

\set _ship_id random(1,700000)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) values(:_ship_id,clock_timestamp(),:x, :y);

pg_bench压测:

[postgres@~]$ pgbench -M prepared -n -r -P 1 -f test.sql -c 80 -j 80 -T 30 -U postgres mytest
transaction type: test.sql
scaling factor: 1
query mode: prepared
number of clients: 80
number of threads: 80
duration: 30 s
number of transactions actually processed: 1102316
latency average = 2.179 ms
latency stddev = 2.590 ms
tps = 36616.746279 (including connections establishing)
tps = 36662.855209 (excluding connections establishing)

tps:36662

2.2 pg自带分区表

2.2.1 list分区

建立表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
) partition by list(ship_id );
create index shiptrack_time_idx on shiptrack using btree(pos_time);

创建分区表,分区数量4:

do language plpgsql $$  
 DECLARE
    i int;
    sql text;
 BEGIN
    for i in 1..4 loop
        sql:=format('create table if not exists shiptrack_%s PARTITION OF shiptrack for values in (%s)',i,i);
        execute sql;
        raise notice '%',sql;
    end loop;
end;  
$$;

测试脚本 test.sql:

\set _ship_id random(1,4)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) values(:_ship_id,clock_timestamp(),:x, :y);

list分区数量4,tps:34492
同理:
list分区数量40,tps:21473
list分区数量400,tps: 3220

2.2.2 hash分区

建立表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
)  partition by hash(ship_id);
create index shiptrack_id_idx on shiptrack using btree(ship_id);
create index shiptrack_time_idx on shiptrack using btree(pos_time);

创建分区表,分区数量4:

do language plpgsql $$  
 DECLARE
    i int;
    sql text;
        tableCount int;
 BEGIN
        tableCount :=4;
    for i in 1..tableCount loop
        sql:=format('create table if not exists shiptrack_%s PARTITION OF shiptrack for VALUES WITH (MODULUS %s, REMAINDER %s)',i,tableCount,i-1);
        execute sql;
        raise notice '%',sql;
    end loop;
end;  
$$;

测试脚本 test.sql:

\set _ship_id random(1,700000)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) values(:_ship_id,clock_timestamp(),:x, :y);

hash分区数量4,tps:32442
同理:
hash分区数量40,tps:20611
hash分区数量400,tps: 3167

2.2 pg_pathman测试(仅hash分区测试)

建立表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
) ;
create index shiptrack_id_idx on shiptrack using btree(ship_id);
create index shiptrack_time_idx on shiptrack using btree(pos_time);

创建分区表,分区数量4:

select create_hash_partitions('shiptrack'::regclass,'ship_id',4,false); 

测试脚本 test.sql:

\set _ship_id random(1,700000)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) values(:_ship_id,clock_timestamp(),:x, :y);

pg_pathman分区数量4,tps:29948
同理:
pg_pathman分区数量40,tps:28267
pg_pathman分区数量400,tps: 23283
pg_pathman分区数量1000,tps: 17922

2.3 citus分布式表分区

2.3.1 citus--逐条插入

注意:citus分布式,各个环境与单机环境配置有差异,不太好同上单独比较
建立表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
) ;
create index shiptrack_id_idx on shiptrack using btree(ship_id);
create index shiptrack_time_idx on shiptrack using btree(pos_time);

创建分区表,分区数量4:

--设置分区数量
set citus.shard_count=4;
--设置副本数量
set citus.shard_replication_factor=2;
--对表进行分区
select create_distributed_table('shiptrack','ship_id','hash');

测试脚本

\set _ship_id random(1,700000)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) values(:_ship_id,clock_timestamp(),:x, :y);

citus分区数量4,tps:25342
同理:
citus分区数量40,tps:26112。
citus分区数量400,tps: 26817。
citus分区数量1000,tps: 26524。
逐条sql插入性能比较稳定。

2.3.2 citus--批量插入

建表和分区同上,只需更新下test.sql脚本为批量操作,单批次数量1000:

\set _ship_id random(1,700000)
\set x random(-180,180)
\set y random(-90,90)
INSERT INTO shiptrack(ship_id,pos_time,lon ,lat) select 
:_ship_id,clock_timestamp(),:x, :y from generate_series(1,1000);

创建表:

drop table if exists shiptrack cascade;
create table shiptrack(
    ship_id int not null, --船舶id
    pos_time timestamp without time zone not null, --坐标时间
    lon numeric not null,  --经度
    lat numeric not null --纬度
) ;
create index shiptrack_id_idx on shiptrack using btree(ship_id);
create index shiptrack_time_idx on shiptrack using btree(pos_time);

--设置分区数量
set citus.shard_count=4;
--执行分区
select create_distributed_table('shiptrack','ship_id','hash');

执行压测语句:

[postgres@~]$ pgbench -M prepared -n -r -P 1 -f test.sql -c 80 -j 80 -T 30 -U postgres mytest

通过设置set citus.shard_count为4,40,400,450,550,700,1000,重试上述步骤,得到tps依次是:
citus分区数量4,tps:1563
同理:
citus分区数量40,tps:1549。
citus分区数量400,tps: 1583。
citus分区数量450,tps: 1115。
citus分区数量550,tps: 1063。
citus分区数量700,tps: 895。
citus分区数量1000,tps: 706。

三 测试现象与总结

单表不分区:tps:36662
数据插入与分区表数量关系测试汇总如下表:

测试方式 分区数 4 分区数 40 分区数 400 分区数 1000
pg自带分区 list 34492 21473 3220 未测试
pg自带分区 hash 32442 20611 3167 未测试
pg_pathman hash 29948 28267 23283 17922
citus hash(单条插入) 25342 26112 26817 26524
citus hash(批量插入) 1563 1549 1583 706

现象:

  • 随着分区表数量增加,除了citus都有性能衰减现象。
  • pg_pathman衰减比较平滑,pg自带的分区表指数级别衰减。
  • pg自带的hash分区,性能稍微弱于自带的list分区。
  • citus单条插入性能与分区数量递增关系几乎没有影响。
  • citus以1000数据量为一批次,在分区数为400之前稳定,从400之后开始平滑衰减。

个人总结:

  • pg11自带的分区,适用于分区数量不大的业务场景。
  • 在单机pg分区中,如果分区数量比较大,建议采用pg_pathman,可以获取更好的性能。
  • 在具备分布式数据节点的前提下,使用citus的分区在插入和查询都能有较好的表现。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容