最初发现是因为项目日志报错:数据库连接超时/被锁。
之后使用 top
命令查看发现,执行时 mysqld
竟然跑满了一整个单核的CPU,但另一个核却几乎完全空闲。因为服务器是双核,故此怀疑是配置文件问题导致 mysqld
无法充分利用可用资源。但更改配置文件后仍然只使用单核,于是打算先从执行的命令上手排查。
添加 慢查询 日志
nano /etc/mysql/mysql.conf.d
,添加如下配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
之后使用 systemctl restart mysql
重启使其生效。
通过慢查询日志发现问题:
一条 delete
语句竟然执行了 50s,一条 update
甚至能执行 80s
缓慢原因
delete
语句使用 not in
条件删除中使用子查询会极大拖慢速度,最简单的解决方案就是建立临时表,使用空间换时间的方法。
update
语句的批量更新是循环一条一条的更新记录,一条记录update一次。这样性能很差,也很容易造成阻塞。
解决方案
DELETE FROM table1 WHERE id NOT IN (SELECT * FROM (SELECT MIN(id) AS min_id FROM table1 GROUP BY apk_time, tid, raw_data) temp)
在子查询外层再套一遍,实现简易的建立临时表的方案。
而 update
语句直接舍弃批量更新,在业务逻辑中逐条更新即可。
最终效果
将 delete
语句降到 0.06s,总体业务逻辑耗时从 120s 骤减到 3s 之内。