慢HDD存储大数据库:筛选无近30天记录的超30天用户并关联Tag表
解决方案:筛选无近30天记录的用户并关联Tag表
核心逻辑
要筛选的是完全没有近30天内记录的用户,而非单条记录早于30天的用户。核心是从用户维度判断,而非单条记录维度。
推荐SQL写法(低IO,适配慢HDD大型库)
方法1:NOT EXISTS(性能最优)
SELECT u.user_id, u.username, t.tag_name, t.tag_id FROM User u INNER JOIN Tag t ON u.user_id = t.user_id WHERE NOT EXISTS ( SELECT 1 FROM User u_sub WHERE u_sub.user_id = u.user_id AND u_sub.TIMESTAMP >= DATE_SUB(NOW(), INTERVAL 30 DAY) )
- 原理:子查询针对每个用户检查是否存在近30天的记录,一旦找到就终止查询,对索引友好
- 好处:只关联符合条件的用户,减少磁盘IO和关联数据量
方法2:GROUP BY聚合筛选
如果需要查看用户的所有历史记录,可先聚合用户的最新记录时间:
SELECT u.*, t.* FROM ( SELECT user_id, MAX(TIMESTAMP) AS latest_record_time FROM User GROUP BY user_id HAVING latest_record_time < DATE_SUB(NOW(), INTERVAL 30 DAY) ) filtered_users INNER JOIN User u ON filtered_users.user_id = u.user_id INNER JOIN Tag t ON u.user_id = t.user_id
- 原理:先找出所有最新记录早于30天的用户,再关联原表和Tag表
- 注意:如果用户只有单条记录,两种方法效果一致;若用户有多条记录,此方法能确保用户整体符合条件
慢HDD数据库性能优化
- 给User表建立联合索引:
CREATE INDEX idx_user_id_timestamp ON User(user_id, TIMESTAMP);
这个索引能让子查询和聚合操作直接定位数据,避免全表扫描,大幅降低磁盘IO。
- 给Tag表建立用户ID索引:
CREATE INDEX idx_tag_user_id ON Tag(user_id);
加速用户与标签的关联查询。
- 避免
SELECT *,只查询业务需要的字段,减少磁盘读取的数据量。
常见错误说明
如果直接写WHERE u.TIMESTAMP < DATE_SUB(NOW(), INTERVAL 30 DAY),会错误保留那些既有旧记录又有近30天记录的用户的旧数据,不符合“用户无近30天内记录”的要求。必须从用户维度做判断,而非单条记录维度。
内容的提问来源于stack exchange,提问作者rafalefighter
相关产品推荐
相关产品推荐

