按两列之一分组数据库行:高效查找重复行的SQL查询方案
解决MySQL/MariaDB中按A或B列查找重复行的高效方案
嘿,我明白你遇到的问题了——原来的子查询方法在处理8万多行数据时慢得离谱,而且逻辑上也不够严谨。咱们来一步步优化这个需求:找出Column A值重复,或者Column B值重复的行,并且返回每组重复行中的任意一条,同时给出重复计数。
为什么你的原查询速度慢?
你原来用的是关联子查询,每一行数据都会触发一次子查询去统计count(*),84000行就意味着要跑84000次查询,相当于重复扫描表几万次,性能能好才怪!而且如果某行的A和B都有重复,这个count还会把两种重复的数量叠加,结果可能不符合预期。
高效优化方案
核心思路是先预统计所有重复的A值和B值,再关联回原表,这样只需要扫描表2次(分别统计A和B的重复),再加上索引的加持,速度会快很多。
第一步:给A、B列建索引(关键!)
先给A和B列单独建索引,这样分组统计重复值的时候可以直接用索引,不用全表扫描:
CREATE INDEX idx_table_a ON table_name(a); CREATE INDEX idx_table_b ON table_name(b);
第二步:查询重复行(返回每组任意一条)
下面的SQL会找出所有A或B重复的组,然后每个组返回一行(这里取每组id最小的行,你也可以改成MAX(id)取最大的):
SELECT t.id, t.name, t.a, t.b, dg.cnt AS duplicate_count FROM ( -- 统计所有重复的A值及其数量 SELECT 'a' AS group_type, a AS group_value, COUNT(*) AS cnt FROM table_name GROUP BY a HAVING cnt > 1 UNION ALL -- 统计所有重复的B值及其数量 SELECT 'b' AS group_type, b AS group_value, COUNT(*) AS cnt FROM table_name GROUP BY b HAVING cnt > 1 ) dg -- 关联原表,找到对应组的行 JOIN table_name t ON (dg.group_type = 'a' AND t.a = dg.group_value) OR (dg.group_type = 'b' AND t.b = dg.group_value) -- 每个重复组只返回一行(这里取id最小的) GROUP BY dg.group_type, dg.group_value HAVING t.id = MIN(t.id);
用你的示例数据测试,会得到这样的结果:
| id | name | a | b | duplicate_count |
|---|---|---|---|---|
| 1 | Lorem ipsum | 1 | Donec | 2 |
| 2 | dolor sit | 2 | rhoncus | 2 |
如果想返回每组id最大的行,把MIN(t.id)改成MAX(t.id)就行,结果会是id=4和id=3,完全符合你的需求。
可选:避免同一行被多次返回
如果某一行的A和B同时存在重复(比如某行A=1且B=rhoncus,而A=1有2行、B=rhoncus有2行),上面的查询会把这行分到两个组里,导致重复返回。如果要避免这种情况,可以用下面的写法,确保每行只返回一次:
SELECT DISTINCT t.id, t.name, t.a, t.b, -- 优先取A的重复计数,没有的话取B的 COALESCE(a_cnt.cnt, b_cnt.cnt) AS duplicate_count FROM table_name t LEFT JOIN ( SELECT a, COUNT(*) AS cnt FROM table_name GROUP BY a HAVING cnt > 1 ) a_cnt ON t.a = a_cnt.a LEFT JOIN ( SELECT b, COUNT(*) AS cnt FROM table_name GROUP BY b HAVING cnt > 1 ) b_cnt ON t.b = b_cnt.b -- 只保留A或B有重复的行 WHERE a_cnt.cnt IS NOT NULL OR b_cnt.cnt IS NOT NULL;
为什么这个方案更快?
- 只需要扫描表2次来统计A和B的重复值,而不是8万多次
- 利用索引快速完成分组统计,避免全表扫描
- 关联操作的开销远低于大量的子查询
这个方案在MySQL 5.7和MariaDB 10.1上都能完美运行,完全适配你的环境。
内容的提问来源于stack exchange,提问作者Daan
相关产品推荐
相关产品推荐

