PostgreSQL表避免重复数据的常见方法及recipe表最佳实践
PostgreSQL表中避免重复数据的最佳实践(针对recipe表)
先明确场景:我们有一张recipe表,结构如下:
| 列名 | 类型 | 是否可为空 | 默认值 |
|---|---|---|---|
| name | text | not null | |
| date | date | not null | |
| ingredients | text[] | not null | |
| calories | integer | not null |
需求是插入新食谱时,避免出现**name和ingredients完全相同**的重复数据,下面分析几种方案并给出最优解:
方案1:哈希生成唯一ID作为主键
这种方法是把name和ingredients拼接后做哈希,生成256位字符串当主键,插入前检查ID是否存在,存在就终止插入。
但这方案有硬伤:数据量到千万级以上时,哈希碰撞的概率会显著上升,没法保证绝对唯一;而且多维护一个哈希ID字段,既占存储又增加计算成本,完全没必要。
方案2:name+ingredients复合主键
这才是靠谱的做法:直接把name和ingredients设为复合主键,利用PostgreSQL的主键唯一性约束自动拦截重复插入。如果遇到重复数据需要更新更准确的calories值,用ON CONFLICT语法就能实现"插新数据/更旧数据"的逻辑。
优势:
- 数据库原生约束兜底,不用在业务层写复杂的检查逻辑,可靠性拉满
- 复合主键会自动创建索引,哪怕表有几百万行,重复检查的效率也极高
- 灵活适配"存在则更新,不存在则插入"的需求
示例代码:
首先给表加上复合主键:
ALTER TABLE recipe ADD PRIMARY KEY (name, ingredients);
然后用下面的语句实现插入或更新:
INSERT INTO recipe (name, date, ingredients, calories) VALUES ('番茄炒蛋', '2024-05-20', ARRAY['番茄', '鸡蛋', '盐'], 150) ON CONFLICT (name, ingredients) DO UPDATE SET calories = EXCLUDED.calories, date = EXCLUDED.date;
方案3:插入前全表比对
每次插入前遍历全表,对比name和ingredients有没有重复,有就更新calories。
这方案完全不适合大规模场景:数据量上千后,全表扫描的速度会慢到离谱,直接拖垮插入性能,纯纯的反面教材。
总结
方案2是绝对的最佳实践:用数据库原生的复合主键保证唯一性,结合ON CONFLICT实现高效的插入更新逻辑,既靠谱又高效,还不用额外维护冗余字段。
内容的提问来源于stack exchange,提问作者adam
相关产品推荐
相关产品推荐

