跳到主要内容

Postgresql Scale

  • scale up
    • 堆硬件
  • scale out replicas
    • 读写分离
    • pub/sub
  • scale out sharding
    • 分片 - 多节点
    • 应用分片 - 逻辑映射
      • 可控性高、特殊场景
    • 服务分片 - cdb、citus
      • 使用简单、要求使用 patten 符合
提示

PostgreSQL 并不是 OLAP 数据库,能力有上限,当发现有更多的时间和资源投入 数据仓库 时,可以考虑选择一个真正的数仓数据库。

Story

Table Partitioning

  • 查询性能提升
    • 当主要查询的数据都在一个分片里时,索引加载到内存使用率更高
  • 当更新和查询单个分片时性能提升
    • 此时可能通过 seq scan 而不需要使用索引,导致随机访问
  • 通过操作分片表来批量操作数据,性能大幅度提高
  • 较少使用的分片可移到更便宜的存储上

当单表大小超过物理内存时,建议分表

提示
  • 分表索引不可以 CONCURRENTLY
    • 除非先 DETACH
  • 分表可以创建 CREATE INDEX ON ONLY
    • 创建后索引是无效的
    • 在单独分片上创建然后 ATTACH
    • 可以使用该方式来创建 UNIQUE 和 PRIMARY KEY
  • 有时候表继承比分片更好用
警告
  • 唯一 限制必须包含所有 partition key columns
  • 不能创建跨表 exclusion constraint
    • 不支持跨分片限制
  • 针对 INSERT 的 BEFORE ROW 触发器无法更改分片
  • 临时表和持久表不可以混用

分表策略

  • 范围 - 例如 时间字段
  • 列表 - 例如 年字段
  • 哈希 - 例如 UUID 字段

常见策略

  • 基于使用场景的冷热数据区分 - 例如 最近一周数据单独表
  • 基于数据本身的逻辑结构区分 - 例如 区域、年份
-- RANGE 分片
-- 创建虚拟表
CREATE TABLE measurement (
city_id int not null,
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);

-- LIST 分片
CREATE TABLE cities (
city_id bigserial not null,
name text not null,
population bigint
) PARTITION BY LIST (left(lower(name), 1));
-- LIST 子表
CREATE TABLE cities_ab
PARTITION OF cities (
CONSTRAINT city_id_nonzero CHECK (city_id != 0)
) FOR VALUES IN ('a', 'b');
-- 默认分片
CREATE TABLE cities_partdef
PARTITION OF cities DEFAULT;

-- HASH 分片
CREATE TABLE orders (
order_id bigint not null,
cust_id bigint not null,
status text
) PARTITION BY HASH (order_id);
-- HASH 子表
CREATE TABLE orders_p1 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE orders_p2 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE orders_p3 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE orders_p4 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 3);

-- 可直接创建索引 - 当增加分片时会对分片加索引
CREATE INDEX ON measurement (logdate);

CREATE TABLE measurement_y2006m02 PARTITION OF measurement
FOR VALUES FROM ('2006-02-01') TO ('2006-03-01');
-- 可修改 TABLESPACE 选择不同存储介质
CREATE TABLE measurement_y2006m03 PARTITION OF measurement
FOR VALUES FROM ('2006-03-01') TO ('2006-04-01')
TABLESPACE fasttablespace;;

-- 分片表可以再分片
CREATE TABLE measurement_y2006m02 PARTITION OF measurement
FOR VALUES FROM ('2006-02-01') TO ('2006-03-01')
PARTITION BY RANGE (peaktemp);

-- 取保开启分片裁剪配置 - 默认开启
select * from pg_settings where name='enable_partition_pruning';

-- 可以直接删除分片表 - 会锁主表
DROP TABLE measurement_y2006m02;
-- 可以排除分片
ALTER TABLE measurement DETACH PARTITION measurement_y2006m02;


-- 单独创建分片,添加校验,导入数据,加入到分片
CREATE TABLE measurement_y2008m02
(LIKE measurement INCLUDING DEFAULTS INCLUDING CONSTRAINTS)
TABLESPACE fasttablespace;
-- 提前创建好 CONSTRAINT - 否则 ATTACH 时还是会创建且需要 ACCESS EXCLUSIVE
ALTER TABLE measurement_y2008m02 ADD CONSTRAINT y2008m02
CHECK ( logdate >= DATE '2008-02-01' AND logdate < DATE '2008-03-01' );
\copy measurement_y2008m02 from 'measurement_y2008m02'
-- possibly some other data preparation work
-- SHARE UPDATE EXCLUSIVE
-- ATTACH 后可以删除创建的 CHECK
-- 如果有 DEFAULT 也会检查,除非创建了排除 CHECK
ALTER TABLE measurement ATTACH PARTITION measurement_y2008m02
FOR VALUES FROM ('2008-02-01') TO ('2008-03-01' );

Logical Replication

警告
  • 不会复制 schema