真正卡住网站的是MySQL中Rows_examined远大于Rows_sent、含Using filesort或temporary的慢SQL;需验证慢日志是否真实写入、正确解析日志字段、按WHERE+ORDER BY建联合索引,并排查PHP层瓶颈。

宝塔面板网站访问慢,光看页面加载时间没用——真正卡住的往往是 MySQL 里那几条反复扫几万行、却只返回 1 行的 SQL。慢查询日志不是“看看有没有慢 SQL”,而是要定位 Rows_examined 远大于 Rows_sent、带 Using filesort 或 Using temporary 的语句,再按 WHERE + ORDER BY 字段建联合索引。
怎么确认慢查询日志真在写入
很多人点了「开启」就以为万事大吉,结果日志文件空着,或者写了一次再没更新。关键得验证:
- 执行
SELECT SLEEP(2)(确保超过long_query_time设置值),然后立刻查日志:tail -n 5 /www/server/data/mysql-slow.log;没这条记录,说明配置没生效 - 运行
SHOW VARIABLES LIKE 'slow_query_log_file';,确认路径和你配置的一致;宝塔 8.x 后部分版本会硬编码到/www/wwwlogs/mysql_slow.log,别只盯着/www/server/data/ - 检查文件权限:
ls -l /www/wwwlogs/mysql_slow.log,属主必须是mysql,否则报错OS errno 13 - Permission denied - 别用相对路径写
slow_query_log_file,MySQL 启动时工作目录不确定,./mysql-slow.log很可能写丢
怎么看懂慢日志里那堆数字
日志不是直接列 SQL,而是结构化文本。重点盯三行:
-
Query_time: 1.234567—— 执行耗时,但单次长不等于问题大;重复出现、且Rows_examined动辄上万的才危险 -
Rows_examined: 42301—— 扫描行数;如果比Rows_sent: 1高几十倍,基本就是全表扫描,缺索引 -
Rows_sent: 1—— 实际返回行数;配合Rows_examined看效率,比值越小,SQL 越“暴力” - 看到
Extra: Using filesort或Using temporary?说明ORDER BY或GROUP BY没走索引,得把排序字段和 WHERE 字段一起进联合索引
建索引前先搞清 WHERE 和 ORDER BY 的组合逻辑
索引不是加了就快,顺序错了等于白搭。比如这条慢 SQL:
SELECT * FROM user WHERE status = 1 AND created_at > '2024-01-01' ORDER BY created_at DESC LIMIT 20;
你以为 INDEX(created_at) 就行?不行。它对 WHERE status = 1 完全无效。正确做法是:
- 优先建
INDEX(status, created_at):左边字段用于等值过滤,右边字段用于范围查询+排序 - 如果还有
ORDER BY id DESC,且id是主键,那不用额外索引——InnoDB 主键聚簇索引天然有序 - 别给
TEXT字段建普通索引,MySQL 会静默截断前 767 字节,导致索引失效;要用就上全文索引 - 高频查询才建索引,低频或写多读少的表加太多索引反而拖慢
INSERT/UPDATE,还吃 Buffer Pool 内存
别只盯着 MySQL 日志,PHP 层慢才是真黑盒
MySQL 慢日志里干干净净,网站还是卡?大概率是 PHP 脚本自己卡住了,比如 curl 等响应、file_get_contents 读远程资源、死循环,这些根本不会记进 MySQL 日志。
- 开 PHP-FPM 慢日志:
request_slowlog_timeout = 1s,日志路径设为/www/wwwlogs/php_slow.log,重启 PHP - 复现卡顿时,立刻查日志:
tail -n 20 /www/wwwlogs/php_slow.log,你会看到类似:script_filename = /www/wwwroot/site/index.php [0x00007f8b1c0a1234] file_get_contents() /www/wwwroot/site/lib/utils.php:45 - 注意阈值别设太小(如 100ms)——日志爆炸;也别太大(如 5s)——漏掉真实瓶颈
- 宝塔自带的「性能分析」页面只看最近 1 小时,且过滤不全,别依赖它当唯一依据
最常被忽略的点:Rows_examined 高往往意味着 WHERE 条件字段类型不匹配(比如字符串字段用数字查询)、隐式类型转换导致索引失效,或者复合索引字段顺序和查询条件完全对不上——这时候建再多索引也没用,得先改 SQL 或字段定义。

















