场景
10月11日,某个用户出现了信息重复推送,导致出现重复数据,影响到了统计。
需要通过用户ID、时间戳、事件,找出相同msgid字段相同的数据,并删除。
已知,表有接近1亿条数据。
解决
查询重复数据
查看表索引,刚好有匹配的索引
sql
KEY `idx_storeid_event_ctime` (`store_id`,`event`,`ctime`),
sql
SELECT
msgid,
COUNT(*) AS duplicate_count,
min(id) as id
FROM
`user_msg_list`
WHERE
store_id = 233
AND ctime > 1728615600
AND ctime < 1728622800
AND `event` = 'EventGroupChat'
GROUP BY
msgid
HAVING
COUNT(*) > 1;
# 查询的时候不要用 order by id desc
# 否则查询的时候,因为缺少id的索引,引起慢查询。
遍历删除
防止删除到其他的数据,所以还得把前边的条件一起放进来
sql
DELETE
FROM
user_msg_list`
WHERE
store_id = 233
AND ctime > 1728615600
AND ctime < 1728622800
AND `event` = 'EventGroupChat'
AND id != 10086
AND msgid !=318692996
项目上完整代码
我用的是thinkphp框架
php
$where = "store_id = 233
AND ctime > 1728615600
AND ctime < 1728622800
AND `event` = 'EventGroupChat'";
$data = Db::table("user_msg_list")->where($where)->field("msgid,COUNT(*) AS duplicate_count,min(id) as id")->group("msgid")->having("COUNT(*) > 1")
->select()->toArray();
foreach ($data as $v) {
$id = $v['id'];
$msgid = $v['msgid'];
$msgIds = Db::table("user_msg_list")
->where($where)
->where("id!={$id}")
->where("msgid", $msgid)
->column("id");
$res = Db::table("user_msg_list")->whereIn('id',$msgIds)->delete();
dump($res);
}
结束
数据太多了,动不动就是几秒都还无结果,3秒无结果的时候我都会停止运行。
防止出现缩表影响到正常业务的开展。