PostgreSQL 基于 inherits 实现分表的示例代码

 更新时间:2026年05月12日 08:54:58   作者:倒流时光三十年  
本文主要介绍了PostgreSQL 基于 inherits 实现分表的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

背景

生产环境有一张 sales_order_full 表数据量达到 3.3 亿. 存储了公司4个大区全量销售数据.并且数据量还在持续增长. 数据量过大对业务功能读写都造成极大的 IO 压力.为保证系统稳定,团队制定了短期的计划,对 sales_order_full  表按大区进行拆分.来减轻单表压力.

首先你需要了解 PostgreSQL 的 inherits  技术

在 PostgreSQL 中,INHERITANCE 是一种特性,允许一个表从另一个表继承属性(如列、约束等)。这意味着,如果一个表继承自另一个表,它将自动获得所有父表的列和约束。这对于简化数据库设计,特别是当你想要在不同的层次中共享相同结构的数据时非常有用。 (解释来自百度)       

分析订单 Full 表

CREATE TABLE "public"."sales_order_full" (
  "id" int8 NOT NULL DEFAULT nextval('sales_order_mixed_id_seq'::regclass),
  "version_number varchar",
  "order_id" varchar(298),
  "country_cd varchar(29)", 
  "product_no" varchar(35),
  "serial_no" varchar(273),
  "qty" int4,
  "fiscal_qtr",
  "order_dt" time,
  PRIMARY KEY ("order_id")
)
  • ID: 自增索引序列.当前索引序列值已很大 
  • order_id: 订单ID,唯一主键
  • country_cd: 通过country_cd 从 sales_geo_config 表中匹配所属大区 (历史原因导致).                                                                                              

拆分思路

  1. 重建 sales_order_full  表
  2. 放弃 sales_order_mixed_id_seq 重建 id 索引.
  3. full 增加区域字段.便于数据分表
  4. 初始化子表并初始化数据
  5. 代码逻辑调整

定义分表

sales_order_full [主表]只做请求转发.不存储任何数据
ales_order_full_cp     存储 geo =  CP 区域数据
sales_order_full_hd存储 geo =  HD 区域数据
sales_order_full_cy存储 geo =  CY 区域数据
sales_order_full_sy存储 geo =  SY 区域数据
sales_order_full_unkonw兜底未匹配出区域的数据 

前期工作

原 sales_order_full 表改名为  sales_order_full_all_data_bak

第一步:创建新 Full 表

CREATE TABLE "public"."sales_order_full" (
  "id" bigserial, -- bigserial 会自动创建名为 sales_order_full_id_seq 自增索引
  "version_number varchar",
  "order_id" varchar(298),
  "country_cd varchar(29)", 
  "product_no" varchar(35),
  "serial_no" varchar(273),
  "qty" int4,
  "fiscal_qtr", 
  "geo", --所属大区
  "order_dt" time,
  PRIMARY KEY ("order_id")
)

第二步: 创建子表

因为分表较少.没有必要动态创建.统一进行分表初始化即可.

inherits 方式创建的子表. 索引需要重新设置.

子表中 id 字段会复用主表中的 ID 自增索引.

CHECK(geo = 'CP') 意思是对 geo 字段进行约束.只能存储 CP 大区数据.

-- 创建子表,并设置 full 表的父子关系
create table IF NOT EXISTS "sales_order_full_cp" (CHECK(geo = 'CP')) 
inherits (sales_order_full);

-- 设置主键信息
ALTER TABLE "sales_order_full_cp" ADD CONSTRAINT "sales_order_full_cp_pkey" 
PRIMARY KEY (order_id);

-- 设置对应索引
CREATE INDEX "sales_order_full_cp_mixed_idx" ON "public"."sales_order_full_cp" 
USING btree (
  "fiscal_qtr",
  "order_id",
  "country_cd"    
);
      

第三步:数据流转子表

处理明确 Geo 的数据

 insert into sales_order_full_cp
 (order_id,geo,country_cd,product_no,serial_no,qty,fiscal_qtr,order_dt,version_number)
 select 
 -- 注意 geo 字段取自 sales_geo_config 表
 a.order_id,b.geo,a.country_cd,a.product_no,a.serial_no,a.qty,a.fiscal_qtr,a.order_dt,version_number
 from 
 sales_order_full_cp_all_data_bak a 
 left join sales_geo_config b on a.country_cd = b.country 
 where b.geo = 'CP';

处理 unkonw 因为这类数据没有明确Geo,所以要设置默认值 'UNKNOWN'

 insert into sales_order_full_unknown
 (order_id,geo,country_cd,product_no,serial_no,qty,fiscal_qtr,order_dt,versionnumber)
 select 
 -- 注意 geo 直接默认
 a.order_id,'UNKNOWN',a.country_cd,a.product_no,a.serial_no,a.qty,a.fiscal_qtr,a.order_dt,versionnumber
 from 
 sales_order_full_cp_all_data_bak a 
 left join sales_geo_config b on a.country_cd = b.country 
 where b.geo is null or b.geo not in ('HD','CY','SY','CP');

第四步:数据对比并清理 sales_order_full_all_data_bak 表

注意这里得 select count(*) from sales_order_full;

再强调一遍: sales_order_full 表不存储任何数据,只做调用的中转。

通过 Explan 查看执行过程(简略):

->  Parallel Index Only Scan using sales_order_full_unknown 
->  Parallel Seq Scan on sales_order_full_cp 
->  Parallel Seq Scan on sales_order_full_cy
->  Parallel Seq Scan on sales_order_sy
->  Parallel Seq Scan on sales_order_full_hd

可以看到.数据来源全部来自5张子表. 

select count(*) from sales_order_full;
result: 330000000  

select count(*) from sales_order_all_data_bak;
result: 330000000

-- 结果相等 直接删,释放数据库空间
drop table  sales_order_all_data_bak; 

第五步:调整代码逻辑

  1. 对 sales_order_full 表查询操作,要求指定 geo 精确分表信息.
select * from sales_order_full where geo = 'HD' and xx = 'xx'
或
select * from sales_order_full_hd where xx = 'xx'
  1. 新增修改操作必须精确到具体子表操作.
 insert into sales_order_full_cp
 (order_id,geo,country_cd,product_no,serial_no,qty,fiscal_qtr,order_dt,version_numer)
 select 
 a.order_id,b.geo,a.country_cd,a.product_no,a.serial_no,a.qty,a.fiscal_qtr,a.order_dt,versionnumber
 from 
 order_inbound inbound
 left join sales_geo_config b on inbound.country_cd = b.country 
 where b.geo = 'CP' and inbound.version_number = '001';



update sales_order_full_cp set order_status = 'Closed' where order_id = 'xx';

疑问1:为什么不用触发器?

有同事疑问,为何不给 sales_order_full 主表创建触发器.这样数据新增就只操作主表.让主表进行转发处理岂不是更方便.

答案自然否定的.起码完全不合适我们. 系统订单全部是批处理的场景.大量数据通过触发器转发会大大降低性能,因为触发器会逐行检查处理.性能损耗无法接受.

疑问2:既然操作都细化到子表. sales_order_full 还有何用?

1.万恶的分页查询场景.假设要全区域分页查询.我们只需操作 sales_order_full 表. 由数据库帮我们完成 limit 和 offset . 不需要自己控制 5 张子表的分页.

2.对子表的结构修改.只需调整 sales_order_full 表.调整会自动同步到子表.

疑问3:为何不用成熟分表方案.如 Sharding-JDBC?

数据库自带的就超好用了.非常轻量.处理只依赖数据库 IO. 不占应用内存

到此这篇关于PostgreSQL 基于 inherits 实现分表的示例代码的文章就介绍到这了,更多相关PostgreSQL inherits分表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!​

相关文章

  • PostgreSQL因大量并发插入导致的主键冲突的解决方案

    PostgreSQL因大量并发插入导致的主键冲突的解决方案

    在数据库操作中,并发插入是一个常见的场景,然而,当大量并发插入操作同时进行时,可能会遇到主键冲突的问题,本文将深入探讨 PostgreSQL 中解决因大量并发插入导致的主键冲突的方法,并通过具体的示例进行详细说明,需要的朋友可以参考下
    2024-07-07
  • PostgreSQL大版本升级的详细流程

    PostgreSQL大版本升级的详细流程

    PostgreSQL版本发布规则,一年一个大版本,一个季度一个小版本;PG遇到的BUG问题,社区会很快进行修复,并在下一个版本中发布,因此有必要进行对数据库版本升级,本文给大家介绍了PostgreSQL大版本升级的详细流程,需要的朋友可以参考下
    2024-04-04
  • PGSQL查询最近N天的数据及SQL语句实现替换字段内容

    PGSQL查询最近N天的数据及SQL语句实现替换字段内容

    PostgreSQL提供了WITH语句,允许你构造用于查询的辅助语句,下面这篇文章主要给大家介绍了关于PGSQL查询最近N天的数据及SQL语句实现替换字段内容的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-03-03
  • postgreSQL中的内连接和外连接实现操作

    postgreSQL中的内连接和外连接实现操作

    这篇文章主要介绍了postgreSQL中的内连接和外连接实现操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • PostgreSql生产级别数据库安装要注意事项

    PostgreSql生产级别数据库安装要注意事项

    这篇文章主要介绍了PostgreSql生产级别数据库安装要注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • Windows下PostgreSQL安装图解

    Windows下PostgreSQL安装图解

    这篇文章主要为大家介绍了如果在Windows下安装PostgreSQL数据库的方法,需要的朋友可以参考下
    2013-11-11
  • PostgreSQL利用递归优化求稀疏列唯一值的方法

    PostgreSQL利用递归优化求稀疏列唯一值的方法

    这篇文章主要介绍了PostgreSQL利用递归优化求稀疏列唯一值的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • PostgreSQL 用户名大小写规则小结

    PostgreSQL 用户名大小写规则小结

    PostgreSQL默认不区分用户名大小写,创建和连接时自动转为小写,使用双引号可强制区分,下面就来介绍一下PostgreSQL 用户名大小写规则,感兴趣的可以了解一下
    2025-06-06
  • Debian中PostgreSQL数据库安装配置实例

    Debian中PostgreSQL数据库安装配置实例

    这篇文章主要介绍了Debian中PostgreSQL数据库安装配置实例,一个简明教程,需要的朋友可以参考下
    2014-06-06
  • PostgreSQL 实现将多行合并转为列

    PostgreSQL 实现将多行合并转为列

    这篇文章主要介绍了PostgreSQL 实现将多行合并转为列的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论