数据去重与重复数据的高效处理策略
在实际业务中,数据去重是一个非常常见的需求,特别是在日志数据、用户操作记录或交易记录等领域。去重不仅仅是删除重复数据,更重要的是按照业务规则保留最有价值的数据记录。
本文将探讨如何在 SQL 中高效地处理重复数据,通过 DISTINCT、ROW_NUMBER() 和 GROUP BY 等方法解决不同场景下的数据去重问题。
一、常见的去重场景
- 用户登录记录:保留每个用户的最新登录记录,删除其他重复记录。
- 订单数据:针对重复订单记录,保留金额最大的订单或最新的订单记录。
- 日志分析:在日志表中去除重复的操作记录,只保留最近一次操作。
二、数据示例
假设有一个用户登录记录表 user_logins,其结构如下:
| id | user_id | login_time | device |
|---|---|---|---|
| 1 | 101 | 2024-01-01 08:30:00 | PC |
| 2 | 101 | 2024-01-02 10:00:00 | Mobile |
| 3 | 102 | 2024-01-01 09:15:00 | PC |
| 4 | 103 | 2024-01-01 14:45:00 | Tablet |
| 5 | 101 | 2024-01-03 11:00:00 | Mobile |
| 6 | 102 | 2024-01-04 16:30:00 | Mobile |
目标:
- 保留每个用户最近一次的登录记录,删除其他重复数据。
三、常用去重方法
1. 使用 DISTINCT 进行简单去重
DISTINCT 用于去除表中完全重复的行,适用于整个记录重复的场景。
SELECT DISTINCT user_id, device
FROM user_logins;
适用场景:
- 适合字段完全相同的简单重复数据。
- 局限性:
DISTINCT只能消除完全重复的行,如果存在时间戳不同但用户相同的记录,将无法处理。
2. 使用 GROUP BY 与聚合函数
通过 GROUP BY 分组和 MAX 函数,可以保留每组中的最新记录。
SELECT user_id, MAX(login_time) AS latest_login
FROM user_logins
GROUP BY user_id;
适用场景:
- 按用户分组,保留每个用户最新的登录时间。
- 局限性:只能返回最大(最新)时间,无法保留完整记录中的其他字段(如设备类型)。
优化版本:使用子查询保留完整记录
SELECT *
FROM user_logins u
WHERE login_time = (SELECT MAX(login_time)FROM user_loginsWHERE user_id = u.user_id
);
- 说明:子查询筛选出每个用户最新的登录时间,再通过主查询返回完整记录。
3. 使用 ROW_NUMBER() 进行去重
ROW_NUMBER() 是 SQL 窗口函数,可以为每组记录生成唯一的序号,从而方便地保留最新或特定排名的记录。
WITH ranked_logins AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY user_idORDER BY login_time DESC) AS rnFROM user_logins
)
SELECT id, user_id, login_time, device
FROM ranked_logins
WHERE rn = 1;
适用场景:
- 适合去除分组内的重复记录,保留每组中最新的一条记录。
- 优势:可以返回完整的记录而不丢失其他字段。
- 局限性:需要数据库支持窗口函数(如 MySQL 8.0+、PostgreSQL、SQL Server)。
4. 使用 DELETE 删除重复数据
如果要直接在表中删除重复记录,可以使用 ROW_NUMBER() 标记重复数据,然后删除排名大于 1 的行。
WITH ranked_logins AS (SELECT id,ROW_NUMBER() OVER (PARTITION BY user_idORDER BY login_time DESC) AS rnFROM user_logins
)
DELETE FROM user_logins
WHERE id IN (SELECT id FROM ranked_logins WHERE rn > 1
);
- 说明:只保留每个用户最新的一条登录记录,删除其余记录。
四、性能对比与优化策略
性能对比
| 方法 | 执行速度 | 复杂度 | 适用场景 |
|---|---|---|---|
DISTINCT | 快 | 简单 | 去除完全重复的行 |
GROUP BY + MAX | 中 | 一般 | 按分组保留最新或最早的记录 |
ROW_NUMBER() | 快 | 一般 | 分组去重并保留完整记录 |
DELETE + ROW_NUMBER() | 中 | 复杂 | 删除分组内多余记录 |
优化建议
- 索引优化:在去重字段(如
user_id和login_time)上创建索引,可以显著提高查询速度。
CREATE INDEX idx_user_login ON user_logins(user_id, login_time DESC);
- 批量处理:对于超大数据量表,使用批量删除或分批次去重,避免锁表或性能瓶颈。
DELETE FROM user_logins
WHERE id IN (SELECT idFROM user_loginsWHERE login_time < NOW() - INTERVAL 30 DAY
);
- 避免全表扫描:在查询时尽量减少无关字段,只查询需要去重的字段,减少数据库 I/O 操作量。
五、实战案例:每日用户登录记录去重
需求描述:
- 保留每个用户最近一次的登录记录,删除多余的历史记录。
WITH ranked_logins AS (SELECT id,ROW_NUMBER() OVER (PARTITION BY user_idORDER BY login_time DESC) AS rnFROM user_logins
)
DELETE FROM user_logins
WHERE id IN (SELECT id FROM ranked_logins WHERE rn > 1
);
结果:
- 每个用户仅保留一条最近的登录记录。
六、总结
DISTINCT适合简单重复数据的去重。GROUP BY+ 聚合函数 是最常用的去重方式,适合按特定规则分组去重。ROW_NUMBER()提供了更强的灵活性,可以按业务规则保留最优记录,删除其他重复数据。- 性能优化:结合索引与批量处理策略,能有效提升大数据量表的去重效率。
通过合理选择去重策略,可以确保数据的唯一性和完整性,同时提升数据库查询性能,保证业务系统的稳定高效运行。
相关文章:
数据去重与重复数据的高效处理策略
在实际业务中,数据去重是一个非常常见的需求,特别是在日志数据、用户操作记录或交易记录等领域。去重不仅仅是删除重复数据,更重要的是按照业务规则保留最有价值的数据记录。 本文将探讨如何在 SQL 中高效地处理重复数据,通过 DI…...
Spring Boot自动装配代码详解
概述 Spring Boot自动装配是其核心特性之一,它能够根据项目中添加的依赖自动配置Spring应用程序。通过自动装配,开发人员可以减少大量的配置工作,快速搭建起一个可用的Spring应用。 关键组件和注解 SpringBootApplication注解 这是Spring Bo…...
渗透测试-非寻常漏洞案例
声明 本文章所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法. 此文章不允许未经授权转发至除先知社区以外的其它平台!࿰…...
122. 买卖股票的最佳时机 II
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/?envTypestudy-plan-v2&envIdtop-interview-150问题分析: 和买卖股票的最佳时机I这题相比,区别就是可以买多只股票虽然同时只能持有一支,但是我们还是可以…...
Python爬虫入门指南:从零开始抓取数据
Python爬虫入门指南:从零开始抓取数据 引言 在大数据时代,数据是新的石油。而爬虫作为获取数据的重要手段,受到了越来越多的关注。Python作为一门强大的编程语言,其简洁易用的特性使得它成为爬虫开发的首选语言。本篇文章将带你…...
Android使用JAVA调用JNI原生C++方法
1.native-lib.cpp为要生成so库的源码文件 2.JNI函数声明说明 NewStringUTF函数会返回jstring JNI函数声明规则 3.JAVA中声明及调用JNI函数 声明: 调用 4.源码地址: gitgithub.com:tonyimax/UpdateTimeByThread.git...
ros常用命令记录
文章目录 1.基本2.rosbag2.1录制rosbag包2.2播放录制的ROS包 3.生命周期4.ROS启动,roslaunch5.ROS消息发布6.ROS消息后台打印监控 1.基本 ros2 topic list #查看话题列表2.rosbag 2.1录制rosbag包 ros2 bag record <topic_name> #记录单个主题消息 ros2 ba…...
UE5材质节点VertexNormalWs/PixelNormalWS
VertexNormalWs顶点法线方向,此节点可以做物体上积雪、青苔等效果 PixelNormalWS像素法线方向...
友元和运算符重载
1. 友元 可以把某些选定的函数看作类的“荣誉函数”,允许它们访问类对象中非公共的成员,就好像它们是类的成员一样,这种函数称为类的友元。友元可以访问类对象的任意成员。 1.1 友元函数 友元函数是一种定义在类外部的普通函数࿰…...
【数据库事务锁的类型:读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁】
数据库事务锁的类型:读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁 一、读锁/写锁1、锁定读 二、悲观锁/乐观锁2.1 悲观锁2.2 乐观锁 三、表锁/页锁/行锁3.1 表级别的S锁、X锁3.2 表级别的意向锁(intention lock) 一、读锁/写锁 对于数据库中并…...
【Motion Builder】配置c++插件开发环境
目录 准备环境构建官方案例另行构建经验分享附录 准备环境 安装Motion Builder 2024并破解安装Qt 5.15.2 截止至2024年12月19日,Qt的在线安装器的默认页面是没有5.15.2版本的。你需要:在“选择组件”界面,选择“Archive”,点击“…...
多线程访问FFmpegFrameGrabber.start方法阻塞问题
一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能,其底层利用javacv的FFmpegFrameGrabber进行拉流、推流,进而实现了视频中转。 …...
MySQL使用记录
char和varchar varchar是可变长的,实际用多少它就占多少,和char不同,char规定多少它就会占多少 varchar的长度是字符个数,不管是数字、英文还是汉字,varchar(10)都可以存10个,而不会出现因为汉字占更多的字…...
【视觉SLAM:六、视觉里程计Ⅰ:特征点法】
视觉里程计(Visual Odometry, VO)是通过处理图像序列,估计摄像头在时间上的相对位姿变化的技术。它是视觉SLAM的重要组成部分之一,主要通过提取图像中的信息(如特征点或直接像素强度)来实现相机运动估计。以…...
Python 数据结构揭秘:栈与队列
栈(Stack) 定义 栈是一种后进先出(Last In First Out, LIFO)的数据结构。它类似于一个容器,只能在一端进行插入和删除操作。栈有两个主要的操作:push(入栈)和 pop(出栈…...
常见的框架漏洞
1.Thinkphp Thinkphp5x远程命令执行及getshell 搭建靶场 cd vulhub/thinkphp/5-rce docker-compose up -d 首页 漏洞根本源于 thinkphp/library/think/Request.php 中method方法可以进行变量覆盖,通过覆盖类的核心属性filter导致rce,其攻击点较为多&…...
在C++中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序;使用python的方案
在C中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序是相当复杂的,因为C本身并不直接提供高级的GUI自动化功能。通常,这样的任务会使用Windows API(如User32.dll中的函数)或者一些第三方库(如UIAutomati…...
《Vue3实战教程》26:Vue3Transition
如果您有疑问,请观看视频教程《Vue3实战教程》...
【架构设计(一)】常见的Java架构模式
常见的 Java 架构模式解析 在 Java 开发领域,选择合适的架构模式对于构建高效、可维护且能满足业务需求的软件系统至关重要。本文将深入探讨几种常见的 Java架构模式,包括单体架构与微服务架构、分层架构与微服务架构的对比,以及事件驱动架构…...
自定义有序Map
package cn.ziqirj.common.utils;import lombok.Getter; import lombok.Setter;import java.util.ArrayList; import java.util.List;/*** 模拟Map集合,key不可重复,按插入顺序排序* author zhangji** param <T>*/ public class CustomOrderlyMap&…...
技术揭秘:如何构建Unity URP高性能卡通渲染着色器
技术揭秘:如何构建Unity URP高性能卡通渲染着色器 【免费下载链接】UnityURPToonLitShaderExample A very simple toon lit shader example, for you to learn writing custom lit shader in Unity URP 项目地址: https://gitcode.com/gh_mirrors/un/UnityURPToon…...
Universal x86 Tuning Utility:解锁被封印的硬件潜能,你的电脑比你想象的更强大
Universal x86 Tuning Utility:解锁被封印的硬件潜能,你的电脑比你想象的更强大 【免费下载链接】Universal-x86-Tuning-Utility Unlock the full potential of your Intel/AMD based device. 项目地址: https://gitcode.com/gh_mirrors/un/Universal-…...
ESP32开发环境搭建:手把手教你搞定Python依赖报错(ESP-IDF 4.x/5.x通用)
ESP32开发环境搭建:手把手教你搞定Python依赖报错(ESP-IDF 4.x/5.x通用) 第一次接触ESP32开发时,看到终端里突然跳出一堆红色报错信息,那种手足无措的感觉我至今记忆犹新。特别是当错误提示"The following Python…...
降AI率工具哪个好?背后的判断逻辑你可能没想过
降AI率工具哪个好?背后的判断逻辑你可能没想过 一、一个被问烂了的问题,却很少有人答对 “降AI率工具哪个好?”——这是2026年毕业季被问得最多的问题之一。打开知乎、小红书、百度贴吧,铺天盖地的测评、排行榜、推荐帖,但真正能帮你做决策的内容寥寥无几。 为什…...
HarmonyOS原子化服务:轻量化应用的未来形态
这里写自定义目录标题HarmonyOS原子化服务:轻量化应用的未来形态引言:移动应用范式的第三次革命第一章:原子化服务的哲学思辨与技术演进1.1 从“应用商店”到“服务生态”的范式转移1.2 原子化服务的技术架构演进第二章:服务卡片&…...
如何设置密码复杂度策略以约束MongoDB用户的密码强度
启用 pwdPolicy 前必须开启 --auth 或 security.authorization: enabled,否则策略被忽略;setSecuritySettings 仅对新用户或手动改密生效;仅 minLength 和 characterClassCount 有效,其他字段未实现。启用 pwdPolicy 前必须开启访…...
2026年降AI工具免费版和付费版区别:哪些场景下付费版才值得买
2026年降AI工具免费版和付费版区别:哪些场景下付费版才值得买 研究生群里聊起AI率的问题,发现十个人里起码六七个都在用工具降。主流的选择其实就那几款,关键是选对了能省很多麻烦。 综合价格和效果,我主推嘎嘎降AI(…...
Logisim搭建16位比较器翻车实录:从四个4位模块到最终调试成功的避坑指南
Logisim搭建16位比较器翻车实录:从四个4位模块到最终调试成功的避坑指南 当你信心满满地将四个4位比较器模块拼接成16位版本时,电路图上那些010状态码突然变得像摩尔斯电码一样难以破译。这不是简单的拼积木游戏——每个中间状态都暗藏玄机,高…...
告别原生局限:手把手教你为QML应用注入KDDockWidgets窗口停靠能力(Windows/Mac双平台配置指南)
突破QML窗口管理瓶颈:KDDockWidgets跨平台整合实战 在构建现代化桌面应用时,窗口停靠系统是提升用户体验的关键组件。然而Qt框架长期存在一个明显的功能缺口——官方QML模块缺乏原生的DockWidget支持。这种局限性迫使开发者要么接受功能残缺,…...
别再只会插上就用了!手把手教你用V4L2在Ubuntu上精细调校USB摄像头(亮度/曝光/白平衡)
从参数盲调到精准控制:V4L2在Ubuntu下的USB摄像头画质调优实战 当你用USB摄像头进行视频会议时,是否遇到过画面忽明忽暗?当你在OpenCV项目中进行图像识别时,是否被偏色问题困扰?大多数Linux用户止步于"摄像头能工…...
