最新项目一直出现线上问题,定位原因看到是由于表数据过大导致的,现在有个登录表,登录游戏玩家每次登录的信息,久而久之,这几个表的数据量达到了两亿多条。每天都在上报,采集,由于没有定期删除,数据大量累积。大概有一年左右的数据,一个表的数据已经达到亿级别的。这样算下来,一个表的数据至少是几十GB了。因此需要删除过期的数据,暂时保留近三个月的统计数据。
解决方案:
基本每个表都有个字段叫create_time或者collect_time的字段,只要删除这个字段三个月之前的数据就ok了
delete from table_name where create_time < '2017-04-06'
只要执行这句SQL应该就可以了
遇到的问题:
The total number of locks exceeds the lock table size in MySQL
因为需要删除的数据太大,mysql给的buffer好像只有8MB左右(网上搜到的)
后面找到DBA帮忙看,问这个表建了索引没有
show index from table_name
通过查看索引,我们在create_time和collect_time上是建了索引的,索引类型是BTree,ASC。这里我们用的Mysql引擎是InnoDb
delete from table_name where create_time < '2017-07-06' order by create_time asc limit 10000
接着,我想用order by + limit实现删除,还是出现了上面的错误
后面DBA提示我说,为啥不用ID删除,说按id删除,速度和按索引列删除,不是一个数量级的
接着我想到了拆分一下。
最终解决方案:
找出符合条件的create_time和collect_time的最大ID
select max(id) from table_name where create_time < '2017-04-06'
这里千万左右的数据大概需要10多秒
接着按id删除,一次删除10k,循环删除
delete from table_name where id < maxId limit 10000
直到把过期的时间删除完成
这里我没有msyql服务器的权限,通过java客户端连接删除,使用的spring jdbcTemplate这个接口
另外,这里一次删除10k还有个原因是,事务太大,影响其他服务的运行
还用到的技术,就是使用线程池来执行sql删除,实现异步删除。和同事吃饭的时候,同事也提供了一个解决方案,每次删一秒的数据,这样一次次的删。看了一下数据,一秒的数据基本在几十万,左右,这样不太好控制数据量大小。还是通过主键id + limit 10k这里稳妥一点。
还有一点就是,为了怕压到mysql服务器,这里线程池删除的时候回sleep(1000),阻塞1s再删除,减轻mysql服务器的压力
今天搞了一下数据删除这一点东西,感觉mysql水很深,比如一个select count(*)的执行过程,select from table_name order by id limit 的过程,索引,各种连接,引擎的工作原理。走的时候还有点没有调完,明天应该可以搞定这些了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有