Redshift表仅mongo_id不同的全字段重复数据删除方法咨询
13亿级Web事件大表非主键维度冗余数据去重方案
首先明确核心判定规则:你的冗余数据判定标准是除mongo_id字段外,其余所有字段取值完全一致,每组重复记录仅保留1条对应的mongo_id即可。
结合你之前熟悉的「建新表-切表-删旧表」的操作骨架,针对超大数据表做适配优化,完全避免直接在原表做行级删除、全表硬扫的性能坑。
大表操作的核心前提
对13亿行规模的表做去重,绝对不能直接跑全表行级DELETE、单线程全表GROUP BY,这类操作会触发海量锁、长事务、主从同步延迟,甚至直接把数据库打挂。所有流程都复用你之前验证过安全的新表迁移逻辑,只调整新表的生成规则。
具体实现步骤
1. 确定重复组的保留规则
针对同一组(除mongo_id外所有字段完全一致)的记录,只需要筛选出要保留的那1条的mongo_id即可,不存在留哪条的对错问题,只要保证每组留1个就行:
- 简单场景直接写分组字段:把除
mongo_id外的全部字段列在GROUP BY子句里,用MIN(mongo_id)或者MAX(mongo_id)选每组要留的mongo_id - 字段特别多的场景用内置哈希函数替代手写分组字段,避免漏写字段导致分组错误:
-- 以PostgreSQL为例,自动计算除mongo_id外的行哈希做分组键 SELECT md5(row(t.*)::text) AS row_hash, MIN(mongo_id) AS keep_mongo_id FROM (SELECT * FROM 你的事件表名) t GROUP BY row_hash-- 以ClickHouse为例,用高效哈希函数计算行值 SELECT cityHash64(除mongo_id外的所有字段) AS row_hash, argMin(mongo_id, mongo_id) AS keep_mongo_id FROM 你的事件表名 GROUP BY row_hash
2. 分片迁移去重结果到新表
13亿行的全量聚合不要一次性跑,利用Web事件表天然带时间分区的特性,逐天/逐周拆分任务并行跑:
- 先创建和原表结构、索引、分区规则完全一致的新表
table_name_new - 按时间分片逐批写入去重后的记录,每个任务只处理1-2周的数据量,避免单任务内存、IO占满:
-- 单天分片写入示例 INSERT INTO table_name_new SELECT 原表.* FROM 你的事件表名 原表 INNER JOIN ( -- 筛选当天时间范围内,每组重复记录要保留的mongo_id SELECT MIN(mongo_id) AS keep_id FROM 你的事件表名 WHERE event_time::date = '2024-01-01' GROUP BY 除mongo_id外的所有字段 ) keep_rule ON 原表.mongo_id = keep_rule.keep_id; - 逐天跑完所有分片后,校验新表的总量、抽样数据和原表是否一致
3. 安全切表流程
等新表数据校验完成,走你之前验证过的切表逻辑,避免切换过程中丢写入:
-- 给原表加短期只读锁,避免切换过程中写入新数据 ALTER TABLE 你的事件表名 SET READ ONLY = 1; -- 重命名完成表切换 ALTER TABLE 你的事件表名 RENAME TO table_name_old; ALTER TABLE table_name_new RENAME TO 你的事件表名; -- 确认新表查询、写入全部正常后,再释放旧表的存储空间 DROP TABLE table_name_old;
常见踩坑提醒
- 不要为了省事在生成新表的时候丢掉真实
mongo_id,比如直接生成随机值、自增ID替代原mongo_id,如果业务链路依赖mongo_id做数据关联,会直接引发全链路数据不一致 - 不要用
NOT IN类的关联做原表删除,哪怕你筛选出了所有要删掉的mongo_id,13亿行的关联删除会产生几倍于建表的临时日志,耗时是建新表的5-10倍 - 跑全表聚合前一定要预留足够的临时磁盘空间,避免任务跑到一半磁盘占满,前功尽弃
内容的提问来源于stack exchange,提问作者Patthebug
相关产品推荐
相关产品推荐

