商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > TP5.1 数据库 CPU 飙升卡顿?利用 EXPLAIN 分析慢查询添加复合索引

TP5.1 数据库 CPU 飙升卡顿?利用 EXPLAIN 分析慢查询添加复合索引

  发布于2026-07-14 阅读(0)

扫一扫,手机访问

先抛出几个核心判断:MySQL索引失效,说白了就是数据库没按你设想的路线走,原因无非那几种典型情况——隐式类型转换、索引列上用了函数或表达式、违反最左前缀原则、OR条件里混了非索引列、索引选择性太低、范围查询后的后缀列失效、前导模糊查询、对索引列做运算、用!=或IS NULL这类操作符,以及数据占比过大导致优化器干脆放弃索引。 TP5.1 项目上线后数据库 CPU 突然飙升到 95% 以上,页面响应超 10 秒,日志里反复出现同一张表的 SELECT 查询,但 WHERE 条件字段明明建了单列索引——问题往往出在多条件联合查询时索引失效,必须用 EXPLAIN 看清真实执行路径,再针对性加复合索引。 TP5.1 数据库 CPU 飙升卡顿?利用 EXPLAIN 分析慢查询添加复合索引 ## 定位高负载 SQL 先进入 MySQL 命令行,执行 **【SET GLOBAL slow_query_log = ON;】** 开启慢日志(如果之前没开过)。同时确认 long_query_time 设为 1 秒:`SET long_query_time = 1;`。 接着查出最近 5 条最耗时的慢 SQL: ```sql SELECT query_time, sql_text FROM mysql.slow_log ORDER BY query_time DESC LIMIT 5; ``` 复制其中一条典型语句,比如: ```sql SELECT id,name,created_at FROM user_order WHERE status = 1 AND is_pay = 1 AND created_at > '2023-01-01' ORDER BY created_at DESC; ``` ## 用 EXPLAIN 看执行计划 在该 SQL 前加上 EXPLAIN 关键字并执行: ```sql EXPLAIN SELECT id,name,created_at FROM user_order WHERE status = 1 AND is_pay = 1 AND created_at > '2023-01-01' ORDER BY created_at DESC; ``` 重点看 **type** 字段——如果显示 `ALL` 或 `index`,说明走了全表扫描或全索引扫描;再看 **key** 字段是否为 `NULL`,`NULL` 就是没走任何索引;**rows** 值如果接近表总行数(比如表有 80 万行,rows 显示 792341),基本可以断定索引失效了。 还需要留意的是,EXPLAIN 结果中的 **Extra** 如果出现 `Using filesort` 或 `Using temporary`,说明排序或分组无法利用索引,这也会极大拖慢速度。 ## 设计复合索引 **第一步**:提取 WHERE 条件中所有等值查询字段,按出现顺序排列。这里的 `status` 和 `is_pay` 都是 `=` 查询,优先放前面;`created_at` 是范围查询(`>`),必须放在等值字段之后,否则后续字段没法命中索引。 **第二步**:把 ORDER BY 字段追加到索引末尾。本例中 ORDER BY `created_at DESC`,而 `created_at` 已经在 WHERE 里作为范围条件,直接复用就行,不需要重复添加。但如果排序字段与 WHERE 中不一致(比如 ORDER BY id),就得额外补上。 **第三步**:生成建索引语句: ```sql ALTER TABLE user_order ADD INDEX idx_status_ispay_ctime (status, is_pay, created_at); ``` 这里字段顺序绝不能搞错。如果写成 `(created_at, status, is_pay)`,MySQL 在遇到 `created_at > '2023-01-01'` 时,后面两个等值字段就完全失效了——**复合索引最左前缀原则不可绕过**。 ## 验证索引生效 验证方法有三条路可走。**方法一**:再次执行 EXPLAIN,确认 key 列显示为 `idx_status_ispay_ctime`,type 变成 `ref` 或 `range`,rows 值从几十万降到几百或几千。**方法二**:用 FORCE INDEX 强制走新索引对比性能: ```sql SELECT id,name,created_at FROM user_order FORCE INDEX(idx_status_ispay_ctime) WHERE status = 1 AND is_pay = 1 AND created_at > '2023-01-01' ORDER BY created_at DESC; ``` **方法三**:观察线上监控——`top -H` 查看 mysqld 进程线程 CPU 占用,5 分钟内应从 95%+ 降至 30% 以下;同时用 `SHOW PROCESSLIST` 观察该 SQL 的 Time 值,是否从数百秒降至 0.x 秒。
本文转载于:https://www.php.cn/faq/2820059.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注