MySQL数据库慢查询优化,解决网站卡顿
网站卡顿不一定是服务器配置低,数据库慢查询往往是隐藏原因。
本文按运维排错思路,带零基础用户开启慢查询日志、定位执行超时的SQL、用EXPLAIN分析瓶颈,再通过索引优化解决卡顿。
先确认慢查询是否真的存在
MySQL默认不记录慢查询,需要手动开启。
登录数据库后执行:
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
如果slow_query_log为OFF,说明日志未开;long_query_time默认10秒,生产环境建议调低到1秒或更低。
临时开启(重启失效):
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_output = 'TABLE';
日志输出到mysql.slow_log表,方便直接查询。
若要持久化,需修改配置文件my.cnf(Linux)或my.ini(Windows),在[mysqld]段加入:
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log
log_output = FILE
修改后重启MySQL服务:
systemctl restart mysqld
宝塔面板用户可在“数据库”->“性能调整”中开启慢查询日志,并设置阈值。
找出拖慢网站的SQL语句
如果日志输出到表,直接查询:
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 20;
若输出到文件,用mysqldumpslow工具汇总:
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
参数-s t按总耗时排序,-t 10显示前10条。
重点关注Query_time高、Lock_time高的语句。
拿到具体SQL后,用EXPLAIN分析执行计划:
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';
查看type列:ALL表示全表扫描,index或ref较好;rows列预估扫描行数,
越小越好;Extra出现Using filesort或Using temporary往往需要优化。
索引优化与SQL改写
多数慢查询是因为缺索引或索引失效。
例如WHERE user_id = ?,可建联合索引:
AND status = ?
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
注意联合索引最左前缀原则,查询条件必须包含user_id才能用上该索引。
避免在索引列上使用函数或运算,比如WHERE DATE(created_at) = '2025-01-01'会导致索引失效,应改为范围查询:
WHERE created_at >= '2025-01-01' AND created_at < '2025-01-02'
如果SQL本身写得复杂,比如多表JOIN未走索引,可拆成简单查询或在应用层缓存结果。
避坑指南
不要盲目加索引,写多读少的表索引过多会拖慢插入更新。
long_query_time不要设成0,否则记录所有查询,日志膨胀影响性能。
修改my.cnf前先备份,重启前用mysqld --validate-config检查语法。
生产环境避免在业务高峰执行ALTER TABLE,大表加索引可能锁表,建议用pt-online-schema-change等工具。
效果验证
优化后再次执行原慢SQL,观察执行时间是否下降。
用以下命令确认索引生效:
SHOW INDEX FROM orders;
EXPLAIN SELECT ...;
若type从ALL变为ref,rows明显减少,说明索引起作用。
同时观察网站响应速度,可用ab或curl -w测试页面加载时间:
curl -o /dev/null -s -w '总耗时: %{time_total}s\n' https://你的域名
持续监控慢查询日志,定期用mysqldumpslow复查,防止新的慢SQL产生。
常见疑问
开启慢查询日志会影响性能吗? 会有一点I/O开销,但通常可忽略,建议在业务低峰开启并定期清理日志。
为什么加了索引还是慢? 可能是索引选择错误、统计信息过期,可执行ANALYZE TABLE 表名;更新统计信息。
慢查询日志文件太大怎么办? 可配置logrotate切割,或临时关闭日志,清理后重新开启。
按以上步骤排查优化,多数由数据库引起的网站卡顿都能定位并解决。
如果问题依旧,需检查服务器CPU、内存、磁盘I/O等资源是否瓶颈。