SQL中如何基于EventCode存在情况高效筛选目标去重ID
原SQL性能差的核心原因
- 逻辑错误:自关联子查询里
ev.id = ev.id是恒真条件,还存在字段引用笔误:本来应该判断EventCode是否属于指定编码集合,错写成拿ev.id和EventCode的枚举值做比较,根本没有按ID维度排查是否关联了指定编码,结果集本身就不准 - 无意义的全表计算:需求不需要取每个ID的最新事件、也不需要返回EventCode字段,硬对全表百万级数据做窗口函数排序,是不必要的性能开销
高效实现方案(按执行速度从优到劣排序)
方案1:IN过滤实现(适合常规场景)
利用IN子查询先快速捞出所有关联了指定EventCode的ID,外层直接排除这批ID即可:
SELECT DISTINCT id FROM eventTable WHERE id NOT IN ( SELECT DISTINCT id FROM eventTable WHERE EventCode IN ('A01G0','A01G2','N0030','N0032','UN030') )
注意:如果
eventTable.id存在NULL值,NOT IN语法会因为NULL的三值逻辑返回空结果,这种场景请改用方案2
方案2:LEFT JOIN反连接实现(无NULL坑)
先把全量ID做去重缩成数千行的小结果集,再和已捞取的“带指定EventCode的ID集合”做关联,取未匹配的ID:
SELECT all_id.id FROM ( -- 先做全量ID去重,得到所有唯一ID的小结果集 SELECT DISTINCT id FROM eventTable ) all_id LEFT JOIN ( -- 先过滤出所有命中指定EventCode的ID集合 SELECT DISTINCT id FROM eventTable WHERE EventCode IN ('A01G0','A01G2','N0030','N0032','UN030') ) matched_id ON all_id.id = matched_id.id WHERE matched_id.id IS NULL
配套性能优化建议
- 给
eventTable建立(EventCode, ID)的联合覆盖索引,两个方案的子查询都可以直接走索引扫描,不需要回表读原始行,性能可以提升10~100倍 - 完全不需要保留原来SQL里的
ROW_NUMBER()窗口排序逻辑,这部分对当前需求没有任何作用,只会额外拖慢执行速度
内容的提问来源于stack exchange,提问作者user14065682
相关产品推荐
相关产品推荐

