v11文档
PostgreSQL支持三种分表方式:范围分区(RANGE)、列表分区(LIST)和哈希分区(HASH)。
- 范围分区(RANGE):按照某列(或某几列)的值划分成互不重叠的区间,如按时间按月划分订单表。
- 列表分区(LIST):按照枚举出的值进行分区,例如按国家划分客户表。
- 哈希分区(HASH):根据某列(或某几列)的哈希值对模取余,余数相同的划分到同一分区,如按产品编号哈希分区的产品表。
PostgreSQL 10.x版本之前,分表需要使用继承和触发器来实现,但从PostgreSQL 10.x版本开始,引入了声明式的分表方式,更加简化操作。
版本特性:
- PostgreSQL 11 引入了声明式分表的功能,支持HASH分区方法,并自动传播约束、索引、触发器等到子表。
- PostgreSQL 12 进一步提升了声明式分表性能,支持CHECK约束、INSERT ON CONFLICT、SELECT FOR UPDATE等操作自动路由到子表。
PostgreSQL 15 增加了对IDENTITY列、生成列、排除约束等的支持,以及改进了查询优化器对分区谓词的处理。
练习 以地区和时间进行分区
表 fire_points 结构如下
列名 数据类型 长度 小数位数 允许空值 主键 备注 id int4 32 0 FALSE TRUE 火点ID fire_time timestamp 6 0 TRUE FALSE 火点发生时间 province_code char 6 0 TRUE FALSE 省份代码 city_code char 6 0 TRUE FALSE 城市代码 county_code char 6 0 TRUE FALSE 县区代码 town_code varchar 50 0 TRUE FALSE 乡镇代码 latitude numeric 9 6 TRUE FALSE 纬度 longitude numeric 8 6 TRUE FALSE 经度 shape geometry 0 0 TRUE FALSE 空间信息
先根据省份代码列表分区,然后根据时间按月范围分区
DO $$
DECLARE
province_codes VARCHAR[] := ARRAY[
'110000', '120000', '130000', '140000', '150000', '210000', '220000', '230000',
'310000', '320000', '330000', '340000', '350000', '360000', '370000', '410000',
'420000', '430000', '440000', '450000', '460000', '500000', '510000', '520000',
'530000', '540000', '610000', '620000', '630000', '640000', '650000', '710000',
'810000', '820000'
];
province_code CHAR(6);
sql_query TEXT;
BEGIN
-- 1. 创建主分区表 fire_points_partitioned
CREATE TABLE IF NOT EXISTS fire_points_partitioned (
id SERIAL,
fire_time TIMESTAMP,
province_code CHAR(6),
city_code CHAR(6),
county_code CHAR(6),
town_code VARCHAR(50),
latitude NUMERIC(8, 6),
longitude NUMERIC(9, 6),
shape GEOMETRY
) PARTITION BY LIST (province_code);
-- 2. 根据省份代码列表创建对应的分区表
FOREACH province_code IN ARRAY province_codes
LOOP
-- 3. 创建省份分区表
sql_query := format(
'CREATE TABLE IF NOT EXISTS fire_points_partitioned_%s PARTITION OF fire_points_partitioned FOR VALUES IN (%L)',
province_code, province_code
);
EXECUTE sql_query;
END LOOP;
-- 4. 添加索引
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_fire_points_partitioned_province_code ON fire_points_partitioned (province_code)';
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_fire_points_partitioned_fire_time ON fire_points_partitioned (fire_time)';
END;
$$;
这样,fire_points_partitioned表将根据省份代码进行列表分区,并在province_code和fire_time字段上添加索引。