主键重复定位 SQL

定位重复不止要计数,还要看清重复行内容:把重复组与明细行一起打印,比较加载时间、来源标记等字段,能快速判断是重跑叠加还是关联放大。

主键重复怎么查

主键重复说明表的声明粒度被破坏:一行本应代表一个业务事件,却出现了多行。定位分三步——先用 GROUP BY 加 HAVING COUNT(1) > 1 找出重复键;再把重复组展开成明细行;最后对比差异字段(加载时间、来源系统、批次号)判断成因。只统计重复数量而不展开明细,只能知道有问题,判断不出是重跑叠加、双写还是关联放大,也就选不出正确的修复方式。

基本信息

适用Hive、Spark SQL、MySQL 8、Doris 等支持窗口函数与 CTE 的引擎
定位步骤找重复键 → 展开明细 → 对比差异字段
关键线索加载时间、来源系统、批次号、是否有重复分区
常见原因重跑未覆盖、双写、关联放大、去重键缺失
修复方向按分区覆盖重写并补自动化校验

典型使用场景

  • 每日稽核发现订单表行数上涨,需要确认是主键重复还是业务正常增长
  • 上游重跑后下游指标偏大,定位是否产生了重复明细
  • 多源合并接入后出现同号多行,排查是双写还是分区未覆盖
  • 关联维度表时误用了一对多关系,导致事实行被放大
  • 迁移或数据回刷后核对粒度声明是否仍成立

重复键展开明细

重复键展开明细
-- 第一步:找重复键(建议用业务键组合,而非单列)
WITH dup AS (
  SELECT order_id, item_no
  FROM dwd_trade_order_detail_di
  WHERE dt = '2026-10-11'
  GROUP BY order_id, item_no
  HAVING COUNT(1) > 1
)
-- 第二步:展开明细并对比差异字段
SELECT d.order_id, d.item_no, d.pay_amount, d.load_time, d.src_sys
FROM dwd_trade_order_detail_di d
JOIN dup ON d.order_id = dup.order_id AND d.item_no = dup.item_no
WHERE d.dt = '2026-10-11'
ORDER BY d.order_id, d.load_time;

-- 第三步:判断是否关联放大(同一批次的重复条数一致多为关联导致)
SELECT load_time, COUNT(1) AS cnt FROM dwd_trade_order_detail_di
WHERE dt = '2026-10-11' GROUP BY load_time ORDER BY cnt DESC LIMIT 10;

重复成因对照

现象常见成因定位线索处理方式
整批行数翻倍重跑未覆盖分区load_time 有两个不同批次按分区覆盖重写
零星同号多行上游双写或补发src_sys 或渠道字段不同与源端约定去重键
按维度汇总后偏大关联一对多放大明细行数正常、汇总偏大改用维表去重或先聚合
特定分区重复任务重试未清理临时区重复仅出现在某天分区先删分区再写入
同时检查多条业务键组合(订单号加明细号)比只查单列更接近真实粒度:很多表的唯一性来自组合键,单列本来就会重复。
把批量重跑造成的重复当偶发问题处理,而不补自动化校验,同一故障会在下次重跑时原样复现,且往往在指标已经对外发布之后才被发现。
修复优先级是先核对粒度声明,再改写数据:如果实际的唯一键是组合键而非单列,正确做法是更新表声明与校验规则,而不是硬把数据压成单列唯一。

易错点

  • 只看重复计数不展开明细,无法判断重复来源,修复方式靠猜
  • 用单列做主键校验,而真实粒度是组合键,长期误报掩盖真问题
  • 把重跑造成的重复当偶发问题,未加自动化校验,下次重跑再次发生
  • 修复时直接按主键任意保留一行,丢掉金额更大的那条明细,造成金额口径偏差

数据来源与参考

  • 行业数据质量稽核实践(重复数据定位)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌