最近163邮箱总是收到RDS的报警邮件。

我赶紧登录了一下RDS,看下具体什么情况。从下面我们可以看到目前的存储空间是600G,已经用了527G。

按照目前项目的业务量的话,不应该有这么多数据的,我们用一条sql来看一下有哪些大表。
SELECT file_name, concat(TOTAL_EXTENTS,’M’) as ‘FIle_size’ FROM INFORMATION_SCHEMA.FILES order by TOTAL_EXTENTS DESC

我们可以看到有三个log表就将近占据了450个G。经过技术部和业务部门的讨论,按照我们目前的业务,只要保留最近3天的就可以了。
那么有的朋友会问为什么会产生这么多数据呢?有以下两个原因:
- 有部分log表是对接的第三方服务,一开始不是很稳定,出问题的时候需要我们这边提供详细的信息给第三方,所以前期一直没有删除数据
- 前期业务没有起来,数据一直不多,就没重视,后期业务起来了,log表就越来越大了。
既然现在出现了这个问题,那么我们就得解决。我们首先看下其中一个表的数据有多少

我们可以看到表的数据有7600万条,那么我们如何来删除多余的数据呢?
解决思路:
(1)首先,表的话有7600万条数据,不建议直接delete或者truncate全表,如果这样操作的话,rds配置不高的情况下可能就直接挂掉了。
(2)将大的问题分解成小的问题,然后通过解决一个一个的小问题,最后大问题也就解决了。因此,我们的建议是用脚本定期来删除。每一次脚本执行10条sql,每条sql删除10万数据,脚本时间可以是半个小时执行一次,或者一个小时执行一次。具体脚本的删除记录数跟执行频率数,大家根据RDS的配置来定。
(3)删除数据的话,不能影响到公司的正常业务。大多数情况下都建议半夜来执行,因为那时候客户是最少的。
(4)经过前面3个步骤,基本上就只保留了3天的数据了,那么接下来我们就要执行以下的567步了。
(5)选择不删除的行导入到原表结构相同的空表中
INSERT INTO t_copy SELECT * FROM t WHERE … ;
(6)使用RENAME TABLE将原来的表命名为备份表,并将副本重命名为原来的名称
RENAME TABLE t TO t_old, t_copy TO t;
(7)删除原来的表
DROP TABLE t_old;
下面我们来开始实际操作
以下是脚本代码:
public function actionDel() { $path = __DIR__; chdir($path); /** * 查出ID最小的一条数据 */ $minRecord = Log::getMinOne(); /** * 用当前时间减去最小记录的创建时间,如果小于等于3,那么就需要删除了 */ $diffDay = (int)((time() - $minRecord['create_time']) / 86400); if ($diffDay <= 3) { echo 'end'; exit; } /** * 每次删除一百万条数据,分10条sql执行,每条sql删除十万条数据,删除的时候利用ID区间去删除,这样的话更好得利用索引 */ $minId = $minRecord['id']; $number = 1000000; $pageSize = 100000; $count = $number / $pageSize; for ($i = 1; $i <= $count; $i++) { $startId = $minId + ($i - 1) * $pageSize; $sql = 'delete from ' . Log::tableName() . ' where id>' . $startId . ' and id<=' . ($startId + $pageSize); echo $sql . PHP_EOL; \Yii::$app->db->createCommand($sql)->execute(); } echo 'success'; }
/** * @return array * @throws \yii\db\Exception */ public static function getMinOne(): array { $sql = 'SELECT * FROM `log` ORDER BY `id` ASC LIMIT 1'; return Yii::$app->db->createCommand($sql)->queryOne(); }
我们在脚本执行前要先手动执行一次,来验证sql的效率,如果执行太慢或者RDS的负载上去了,那么对应的脚本就要修改。

我们从这可以看到,RDS的负载基本没有太大的问题。那么接下来我们就执行5,6,7步就可以了。最终优化后的效果

大家可能会有疑问,为什么删除了将近100G的数据,最后空间只减少12个G呢,那么因为在跑脚本的这个期间,其他的log表的数据又变大了,RDS又扩容了100个G。

后续的log表也可以按照前面的步骤来执行。
参考链接: