76人参与 • 2026-05-12 • MsSqlserver
生产环境有一张 sales_order_full 表数据量达到 3.3 亿. 存储了公司4个大区全量销售数据.并且数据量还在持续增长. 数据量过大对业务功能读写都造成极大的 io 压力.为保证系统稳定,团队制定了短期的计划,对 sales_order_full 表按大区进行拆分.来减轻单表压力.
在 postgresql 中,inheritance 是一种特性,允许一个表从另一个表继承属性(如列、约束等)。这意味着,如果一个表继承自另一个表,它将自动获得所有父表的列和约束。这对于简化数据库设计,特别是当你想要在不同的层次中共享相同结构的数据时非常有用。 (解释来自百度)
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")
)
| 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
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');
注意这里得 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;
select * from sales_order_full where geo = 'hd' and xx = 'xx' 或 select * from sales_order_full_hd where xx = 'xx'
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';
有同事疑问,为何不给 sales_order_full 主表创建触发器.这样数据新增就只操作主表.让主表进行转发处理岂不是更方便.
答案自然否定的.起码完全不合适我们. 系统订单全部是批处理的场景.大量数据通过触发器转发会大大降低性能,因为触发器会逐行检查处理.性能损耗无法接受.
1.万恶的分页查询场景.假设要全区域分页查询.我们只需操作 sales_order_full 表. 由数据库帮我们完成 limit 和 offset . 不需要自己控制 5 张子表的分页.
2.对子表的结构修改.只需调整 sales_order_full 表.调整会自动同步到子表.
数据库自带的就超好用了.非常轻量.处理只依赖数据库 io. 不占应用内存
到此这篇关于postgresql 基于 inherits 实现分表的示例代码的文章就介绍到这了,更多相关postgresql inherits分表内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论