MySQL处理重复数据完整代码实例

 更新时间:2025年09月24日 09:16:05   作者:kushu7  
在数据库管理中,查找重复值是一项常见需求,下面这篇文章主要介绍了MySQL处理重复数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在数据库管理中,重复数据是最常见的 “隐形杀手” 之一。它不仅会浪费存储空间、拖慢查询速度,还可能导致业务逻辑混乱(如统计结果失真、订单重复处理)。

一、认识重复数据:从 “什么是重复” 开始

重复数据并非仅指完全相同的记录,在实际业务中可分为两类:

  • 完全重复:所有字段值均相同的记录(如误操作导致的重复插入)。
  • 部分重复:核心字段相同但非关键字段不同的记录(如同一用户的重复注册,仅注册时间不同)。

二、检测重复数据:

1. 检测完全重复记录

-- 查找完全重复的记录
SELECT * FROM table_name
WHERE (col1, col2, ..., coln) IN (
SELECT col1, col2, ..., coln
FROM table_name
GROUP BY col1, col2, ..., coln
HAVING COUNT(*) > 1
);

适用于所有字段均需唯一的场景(如配置表、字典表):

示例:检测user_config表中完全重复的配置记录:

SELECT * FROM user_config
WHERE (user_id, config_key, config_value) IN (
SELECT user_id, config_key, config_value
FROM user_config
GROUP BY user_id, config_key, config_value
HAVING COUNT(*) > 1
);

2. 检测部分重复记录(按核心字段)

适用于仅需保证核心字段唯一的场景(如用户表的手机号、订单表的订单号):

-- 按核心字段分组,查找重复记录
SELECT core_col1, core_col2, COUNT(*) AS duplicate_count
FROM table_name
GROUP BY core_col1, core_col2
HAVING COUNT(*) > 1;

示例:检测users表中重复的手机号(核心字段为phone):

-- 查看重复手机号及重复次数
SELECT phone, COUNT(*) AS duplicate_count
FROM users
GROUP BY phone
HAVING COUNT(*) > 1;
-- 查看重复手机号对应的完整记录
SELECT * FROM users
WHERE phone IN (
SELECT phone
FROM users
GROUP BY phone
HAVING COUNT(*) > 1
)
ORDER BY phone;

3. 高级检测:带条件的重复记录

结合业务逻辑筛选重复记录(如重复且状态有效的订单):

-- 查找状态为"已支付"的重复订单
SELECT order_no, COUNT(*) AS duplicate_count
FROM orders
WHERE status = 'PAID'
GROUP BY order_no
HAVING COUNT(*) > 1;

4. 使用窗口函数标记重复记录(MySQL 8.0+)

通过ROW_NUMBER()为重复记录编号,便于后续处理:

-- 为重复手机号的记录编号(按注册时间排序)
SELECT
id, phone, register_time,
ROW_NUMBER() OVER (PARTITION BY phone ORDER BY register_time) AS rn
FROM users;
  • 结果中rn > 1的记录即为需要处理的重复数据。

三、删除重复数据:保留有效记录

删除重复数据的核心原则是:保留一条有效记录(如最新 / 最早的记录),删除其余重复项。以下是 4 种实用方法:

1. 带唯一标识的重复记录删除(推荐)

若表中有自增主键(如id),可通过子查询定位并删除重复记录:

-- 保留重复手机号中id最小的记录(即最早插入的记录)
DELETE FROM users
WHERE id NOT IN (
SELECT min_id FROM (
-- 子查询嵌套避免"不能从同表查询并删除"的限制
SELECT MIN(id) AS min_id
FROM users
GROUP BY phone
HAVING COUNT(*) > 1
) AS temp
);

逻辑解析

  1. 内层子查询找出每组重复记录中的最小id(要保留的记录)。
  1. 外层删除所有id不在保留列表中的记录。

2. 无唯一标识的重复记录删除

若表无主键,可通过所有字段组合定位重复记录:

-- 保留完全重复记录中一条(需指定所有字段)
DELETE t1 FROM table_name t1
JOIN table_name t2
ON t1.col1 = t2.col1
AND t1.col2 = t2.col2
AND ...
AND t1.coln = t2.coln
WHERE t1.ctid < t2.ctid; -- 利用隐藏列ctid区分物理位置(仅InnoDB有效)

3. 按条件保留记录(如最新记录)

通过排序保留指定条件的记录(如最新注册的用户):

-- 保留重复手机号中注册时间最新的记录
DELETE t1 FROM users t1
JOIN users t2
ON t1.phone = t2.phone
AND t1.register_time < t2.register_time; -- t1为旧记录

4. 批量删除大表重复数据(性能优化)

当表数据量超过 100 万行时,直接删除可能导致锁表,建议分批次处理:

-- 每次删除1000条重复记录(循环执行至无重复)
DELETE FROM users
WHERE id IN (
SELECT id FROM (
SELECT id
FROM (
SELECT
id,
ROW_NUMBER() OVER (PARTITION BY phone ORDER BY register_time) AS rn
FROM users
) AS t
WHERE rn > 1
LIMIT 1000 -- 限制单次删除数量
) AS temp
);

注意事项:

  • 删除前必须备份:执行CREATE TABLE users_backup AS SELECT * FROM users;创建备份表。
  • 使用事务:通过BEGIN; DELETE ...; COMMIT;确保删除可回滚。
  • 删除后优化:执行OPTIMIZE TABLE users;回收碎片空间。

四、预防重复数据:从源头阻断

处理重复数据的最佳方式是提前预防,以下是 3 种核心手段:

1. 建立唯一约束(最有效)

通过唯一索引主键强制核心字段唯一:

-- 为手机号添加唯一索引,阻止重复插入
CREATE UNIQUE INDEX uk_users_phone ON users(phone);
-- 复合唯一索引(如同一用户的配置键唯一)
CREATE UNIQUE INDEX uk_user_config ON user_config(user_id, config_key);
  • 插入重复数据时,MySQL 会直接报错(Duplicate entry),避免污染数据。

2. 插入时处理重复数据

通过INSERT ... IGNORE或REPLACE INTO在插入阶段处理重复:

-- 插入时忽略重复记录(不报错,返回警告)
INSERT IGNORE INTO users (phone, name)
VALUES ('13800138000', '张三');
-- 重复时替换旧记录(删除旧记录后插入新记录)
REPLACE INTO users (phone, name)
VALUES ('13800138000', '张三');
  • 适用场景:数据同步、批量导入等可能产生重复的场景。

3. 业务层控制

在应用程序中添加重复校验逻辑:

// Java示例:插入前检查手机号是否已存在
public boolean addUser(User user) {
// 先查询是否存在重复手机号
if (userDao.existsByPhone(user.getPhone())) {
throw new DuplicateException("手机号已注册");
}
return userDao.insert(user) > 0;
}
  • 配合数据库唯一索引,形成 “双重保障”。

总结

到此这篇关于MySQL处理重复数据的文章就介绍到这了,更多相关MySQL处理重复数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL分区之RANGE分区详解

    MySQL分区之RANGE分区详解

    Range分区是最常用的一种分区类型,它是根据某个列的值划分为几个连续的区,行数据根据该列的值分别放入到不同的分区,这篇文章主要给大家介绍了关于MySQL分区之RANGE分区的相关资料,需要的朋友可以参考下
    2022-04-04
  • 安装rpm包时提示错误:依赖检测失败的解决方法

    安装rpm包时提示错误:依赖检测失败的解决方法

    今天在虚拟机中装MySQL的时候,突然出现了这个依赖检测错误,下面这篇文章主要给大家介绍了关于安装rpm包时提示错误:依赖检测失败的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • 用HAProxy来检测MySQL复制的延迟的教程

    用HAProxy来检测MySQL复制的延迟的教程

    这篇文章主要介绍了用HAProxy来检测MySQL复制的延迟的教程,HAProxy需要使用到PHP脚本,需要的朋友可以参考下
    2015-04-04
  • 一篇文章带你了解MySQL数据库约束

    一篇文章带你了解MySQL数据库约束

    数据库中要管理很多数据,但是这些数据是否正确、是否非法,光靠人力来检验是远远不够的,因此我们想让数据库拥有丰富的检验和校验能力,所以便引入了约束,下面这篇文章主要给大家介绍了关于MySQL数据库约束的相关资料,需要的朋友可以参考下
    2023-06-06
  • MySQL5.6基本优化配置

    MySQL5.6基本优化配置

    这篇文章主要介绍了MySQL5.6基本优化配置,详细分解了MySQL5.6需要优化的配置项,最终给出了一个优化案例,需要的朋友可以参考下
    2014-06-06
  • 一次MySQL慢查询导致的故障

    一次MySQL慢查询导致的故障

    这篇文章主要介绍了如何对MySQL慢查询导致的故障进行处理,慢查询是我们在mysql中经常需要使用到的一个很方便的功能,慢查询对于跟踪有问题的查询很有用,需要的朋友可以参考下
    2015-08-08
  • mysql整数数据类型深入解析

    mysql整数数据类型深入解析

    本篇文章是对mysql中的整数数据类型进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • MYSQL中EXISTS的用法小结

    MYSQL中EXISTS的用法小结

    在MySQL数据库中,EXISTS是一种强大的工具,用于处理复杂的查询需求,本文主要介绍了MYSQL中EXISTS的用法小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • SQL Server服务器监控

    SQL Server服务器监控

    这篇文章主要介绍了SQL Server服务器监控,SQL server监控是收集、聚合和监控SQL服务器的各种指标的过程,更多相关内容需要的朋友可以参考一下
    2022-09-09
  • 史上最简单的MySQL数据备份与还原教程(下)(三十七)

    史上最简单的MySQL数据备份与还原教程(下)(三十七)

    这篇文章主要为大家详细介绍了史上最简单的MySQL数据备份与还原教程下篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10

最新评论