一、概述
1.1 背景介绍
上周四下午三点,业务方反馈后台管理系统加载特别慢,一个列表页面要等 30 多秒。登上数据库一看,一条查询跑了 28 秒。这种场景在电商大促、月底结算等业务高峰期尤其常见——平时跑得好好的 SQL,数据量一上来就原形毕露。
MySQL 慢查询优化是 DBA 和后端开发的必修课。但现实是,很多团队的处理方式就是”加索引碰运气”,加一个不行再加一个,最后索引加了一堆,查询还是慢。
这篇文章分享一套系统化的慢查询排查和优化方法,从定位问题 SQL、分析执行计划、设计合理索引,到验证优化效果,形成闭环。
1.2 技术特点
-
数据驱动:基于 EXPLAIN、执行计划、实际耗时来决策,不靠猜 -
最小改动:优先调整 SQL 和索引,尽量不改业务逻辑 -
可验证:优化前后有对比数据,效果可量化 -
可复制:方法论清晰,团队成员都能学会
1.3 适用场景
-
场景一:单条 SQL 执行时间过长,需要优化 -
场景二:数据库整体 QPS 下降,需要找出问题 SQL -
场景三:新功能上线前,需要对 SQL 进行性能评审 -
场景四:数据量增长后,原有 SQL 性能恶化
1.4 环境要求
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
二、详细步骤
2.1 准备工作
2.1.1 开启慢查询日志
慢查询日志是排查的数据源,必须先确保开启。
-- 查看慢查询日志配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
-- 动态开启慢查询日志(临时生效)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 超过 1 秒的查询记录下来
SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 未使用索引的查询也记录
-- 持久化配置(修改 my.cnf)
-- [mysqld]
-- slow_query_log = 1
-- slow_query_log_file = /var/log/mysql/slow.log
-- long_query_time = 1
-- log_queries_not_using_indexes = 1
说明:生产环境建议 long_query_time 设为 1 秒或 2 秒。设太小会产生大量日志,设太大会漏掉一些”不算特别慢但仍有优化空间”的查询。
2.1.2 安装分析工具
# 安装 Percona Toolkit
# CentOS/RHEL
sudo yum install -y percona-toolkit
# Ubuntu/Debian
sudo apt install -y percona-toolkit
# 验证安装
pt-query-digest --version
2.2 第一阶段:定位问题 SQL
2.2.1 慢查询日志分析
# 使用 pt-query-digest 分析慢查询日志
pt-query-digest /var/log/mysql/slow.log > slow_report.txt
# 只看最近 1 小时的慢查询
pt-query-digest --since '1h' /var/log/mysql/slow.log
# 按响应时间排序,取 TOP 10
pt-query-digest --limit 10 /var/log/mysql/slow.log
pt-query-digest 输出解读:
# Profile
# Rank Query ID Response time Calls R/Call
# ==== ================================== =============== ====== ======
# 1 0x4E2B7F6A8D9C1E3F5A7B9D2C4E6F8A1B 1580.2904 48.7% 234 6.7534
# 2 0x1A2B3C4D5E6F7A8B9C0D1E2F3A4B5C6D 892.1156 27.5% 1893 0.4714
# 3 0x7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C 412.3892 12.7% 89 4.6336
重点关注:
-
Response time 占比高:说明这条 SQL 是主要耗时来源 -
Calls 多 + R/Call 高:高频慢查询,优化收益最大 -
R/Call 特别高:单次执行就很慢,可能缺索引或数据量大
2.2.2 实时查看正在执行的慢查询
-- 查看当前正在执行的查询
SHOW FULL PROCESSLIST;
-- 只看执行时间超过 5 秒的
SELECT * FROM information_schema.processlist
WHERE command != 'Sleep' AND time > 5
ORDER BY time DESC;
-- MySQL 8.0+ 可以用 performance_schema
SELECT
thread_id,
sql_text,
timer_wait/1000000000000 AS exec_time_sec,
rows_examined,
rows_sent
FROM performance_schema.events_statements_current
WHERE timer_wait > 5000000000000 -- 5秒
ORDER BY timer_wait DESC;
2.2.3 从监控系统定位
如果有 Prometheus + Grafana 监控,可以通过以下指标定位:
-- 查看各类语句的执行统计
SELECT
DIGEST_TEXT,
COUNT_STAR AS exec_count,
SUM_TIMER_WAIT/1000000000000 AS total_time_sec,
AVG_TIMER_WAIT/1000000000000 AS avg_time_sec,
SUM_ROWS_EXAMINED AS rows_examined,
SUM_ROWS_SENT AS rows_sent
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;
2.3 第二阶段:分析执行计划
找到问题 SQL 后,下一步是理解它为什么慢。
2.3.1 EXPLAIN 基础用法
-- 基础用法
EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
-- 显示更多信息(MySQL 8.0+)
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
-- 实际执行并显示统计信息(MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
2.3.2 EXPLAIN 输出解读
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 982341 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
关键字段解读:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type 从好到差排序:
system > const > eq_ref > ref > range > index > ALL
2.3.3 典型问题模式识别
模式一:全表扫描(type=ALL)
-- 问题 SQL
EXPLAIN SELECT * FROM orders WHERE YEAR(create_time) = 2024;
-- 输出
-- type: ALL, rows: 1000000, Extra: Using where
-- 问题:对 create_time 使用函数,索引失效
-- 优化后
EXPLAIN SELECT * FROM orders
WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';
-- type: range, rows: 50000
模式二:索引失效
-- 问题 SQL(隐式类型转换)
EXPLAIN SELECT * FROM users WHERE phone = 13800138000;
-- phone 是 varchar,传入数字会导致类型转换,索引失效
-- 优化后
EXPLAIN SELECT * FROM users WHERE phone = '13800138000';
模式三:回表过多
-- 问题 SQL
EXPLAIN SELECT * FROM orders WHERE user_id = 12345;
-- type: ref, key: idx_user_id, rows: 500
-- 问题:虽然走了索引,但需要回表 500 次取其他字段
-- 如果只需要部分字段,可以用覆盖索引
EXPLAIN SELECT order_id, amount, status FROM orders WHERE user_id = 12345;
-- 如果有索引 idx_user_id_amount_status(user_id, amount, status)
-- Extra: Using index(覆盖索引,不需要回表)
2.4 第三阶段:索引设计与优化
2.4.1 索引设计原则
原则一:最左前缀原则
-- 有联合索引 idx_a_b_c(a, b, c)
-- 以下查询可以用到索引:
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3
WHERE a = 1 AND c = 3 -- 只能用到 a
-- 以下查询用不到这个索引:
WHERE b = 2
WHERE c = 3
WHERE b = 2 AND c = 3
原则二:区分度高的字段放前面
-- 查看字段区分度
SELECT
COUNT(DISTINCT status) / COUNT(*) AS status_selectivity,
COUNT(DISTINCT user_id) / COUNT(*) AS user_id_selectivity,
COUNT(DISTINCT create_date) / COUNT(*) AS create_date_selectivity
FROM orders;
-- 假设结果:
-- status_selectivity: 0.00001 (只有几个状态值)
-- user_id_selectivity: 0.1 (用户很多)
-- create_date_selectivity: 0.003 (日期分布)
-- 那么索引顺序应该是:(user_id, create_date, status)
-- 而不是:(status, user_id, create_date)
原则三:覆盖索引优化
-- 原查询
SELECT user_id, order_id, amount FROM orders
WHERE user_id = 12345 AND status = 'paid'
ORDER BY create_time DESC LIMIT 10;
-- 设计覆盖索引(包含查询和排序需要的所有字段)
ALTER TABLE orders ADD INDEX idx_cover (user_id, status, create_time, order_id, amount);
-- 执行计划显示 Using index,不需要回表
2.4.2 索引创建实操
-- 创建索引前先检查表结构和现有索引
SHOW CREATE TABLE orders\G
SHOW INDEX FROM orders;
-- 创建索引(生产环境建议用 pt-online-schema-change)
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
-- 使用 pt-osc 在线加索引(不锁表)
pt-online-schema-change \
--alter "ADD INDEX idx_user_status (user_id, status)" \
--execute \
--user=root \
--password=xxx \
D=mydb,t=orders
-- 删除无用索引
ALTER TABLE orders DROP INDEX idx_old_unused;
2.4.3 索引优化验证
-- 优化前后对比
-- 1. 记录优化前的执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid'\G
-- 2. 记录优化前的执行时间
SET profiling = 1;
SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
SHOW PROFILES;
-- 3. 添加索引
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
-- 4. 再次查看执行计划和执行时间
EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid'\G
SELECT * FROM orders WHERE user_id = 12345 AND status = 'paid';
SHOW PROFILES;
三、示例代码和配置
3.1 完整优化案例
3.1.1 案例:订单列表查询优化
原始 SQL(耗时 28 秒):
SELECT
o.order_id,
o.order_no,
o.amount,
o.status,
o.create_time,
u.username,
u.phone
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE o.create_time >= '2024-01-01'
AND o.status IN ('paid', 'shipped')
AND u.username LIKE '张%'
ORDER BY o.create_time DESC
LIMIT 0, 20;
执行计划分析:
EXPLAIN SELECT ...
-- 输出:
-- orders 表: type=ALL, rows=982341
-- users 表: type=eq_ref, rows=1
-- Extra: Using where; Using temporary; Using filesort
-- 问题分析:
-- 1. orders 表全表扫描
-- 2. 使用了临时表和文件排序
优化步骤:
-- 步骤 1:为 orders 表添加复合索引
ALTER TABLE orders ADD INDEX idx_status_time (status, create_time);
-- 步骤 2:调整 SQL,避免 LEFT JOIN 导致索引失效
SELECT
o.order_id,
o.order_no,
o.amount,
o.status,
o.create_time,
u.username,
u.phone
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.status IN ('paid', 'shipped')
AND o.create_time >= '2024-01-01'
AND u.username LIKE '张%'
ORDER BY o.create_time DESC
LIMIT 0, 20;
-- 步骤 3:如果 username 过滤条件区分度高,考虑先查 users
SELECT
o.order_id,
o.order_no,
o.amount,
o.status,
o.create_time,
u.username,
u.phone
FROM users u
INNER JOIN orders o ON o.user_id = u.id
WHERE u.username LIKE '张%'
AND o.status IN ('paid', 'shipped')
AND o.create_time >= '2024-01-01'
ORDER BY o.create_time DESC
LIMIT 0, 20;
优化后执行计划:
-- orders 表: type=range, key=idx_status_time, rows=15234
-- users 表: type=eq_ref, rows=1
-- Extra: Using index condition
效果对比:
-
优化前:28.3 秒 -
优化后:0.18 秒
3.1.2 索引健康检查脚本
-- 查找未使用的索引
SELECT
t.table_schema,
t.table_name,
t.index_name,
t.column_name,
s.rows_read
FROM information_schema.statistics t
LEFT JOIN sys.schema_index_statistics s
ON t.table_schema = s.table_schema
AND t.table_name = s.table_name
AND t.index_name = s.index_name
WHERE t.table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND t.index_name != 'PRIMARY'
AND (s.rows_read IS NULL OR s.rows_read = 0)
ORDER BY t.table_schema, t.table_name, t.index_name;
-- 查找重复索引
SELECT
table_schema,
table_name,
GROUP_CONCAT(index_name) AS duplicate_indexes,
index_columns
FROM (
SELECT
table_schema,
table_name,
index_name,
GROUP_CONCAT(column_name ORDER BY seq_in_index) AS index_columns
FROM information_schema.statistics
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
GROUP BY table_schema, table_name, index_name
) t
GROUP BY table_schema, table_name, index_columns
HAVING COUNT(*) > 1;
3.2 慢查询自动分析脚本
#!/bin/bash
# 文件名:analyze_slow_queries.sh
# 功能:定期分析慢查询日志,生成报告
set -e
# 配置
MYSQL_SLOW_LOG="/var/log/mysql/slow.log"
REPORT_DIR="/var/log/mysql/reports"
MYSQL_USER="monitor"
MYSQL_PASS="your_password"
MYSQL_HOST="localhost"
# 创建报告目录
mkdir -p $REPORT_DIR
# 生成报告文件名
REPORT_FILE="$REPORT_DIR/slow_query_$(date +%Y%m%d_%H%M%S).txt"
echo "=== MySQL 慢查询分析报告 ===" > $REPORT_FILE
echo "生成时间: $(date '+%Y-%m-%d %H:%M:%S')" >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 1. 使用 pt-query-digest 分析
echo "【1. TOP 10 慢查询】" >> $REPORT_FILE
pt-query-digest --limit 10 $MYSQL_SLOW_LOG >> $REPORT_FILE 2>/dev/null
# 2. 统计信息
echo "" >> $REPORT_FILE
echo "【2. 统计汇总】" >> $REPORT_FILE
echo "慢查询总数: $(grep -c "^# Time:" $MYSQL_SLOW_LOG 2>/dev/null || echo 0)" >> $REPORT_FILE
echo "日志文件大小: $(du -h $MYSQL_SLOW_LOG | cut -f1)" >> $REPORT_FILE
# 3. 当前数据库状态
echo "" >> $REPORT_FILE
echo "【3. 当前数据库状态】" >> $REPORT_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -h$MYSQL_HOST -e "
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Threads_running';
" >> $REPORT_FILE 2>/dev/null
# 4. 发送报告(可选)
# mail -s "MySQL 慢查询日报" dba@example.com < $REPORT_FILE
echo "报告已生成: $REPORT_FILE"
# 5. 轮转日志(可选)
# mv $MYSQL_SLOW_LOG ${MYSQL_SLOW_LOG}.$(date +%Y%m%d)
# mysqladmin -u$MYSQL_USER -p$MYSQL_PASS flush-logs
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 SQL 编写规范
-
**避免 SELECT ***:只查询需要的字段,减少数据传输和内存消耗 -- 差 SELECT * FROM orders WHERE user_id = 12345; -- 好 SELECT order_id, amount, status, create_time FROM orders WHERE user_id = 12345; -
避免在索引列上使用函数: -- 差(索引失效) SELECT * FROM orders WHERE DATE(create_time) = '2024-01-01'; -- 好(可以使用索引) SELECT * FROM orders WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02'; -
使用 LIMIT 限制返回行数: -- 即使需要全量数据,也建议分批获取 SELECT * FROM large_table WHERE conditions LIMIT 0, 10000; SELECT * FROM large_table WHERE conditions LIMIT 10000, 10000;
4.1.2 索引管理规范
-
索引不是越多越好:每个索引都会增加写入开销,一般单表索引控制在 5-6 个以内 -
定期清理无用索引: -- 查找 30 天内未使用的索引 SELECT * FROM sys.schema_unused_indexes WHERE object_schema NOT IN ('mysql', 'sys'); -
大表加索引要用在线工具: # pt-online-schema-change 在线加索引 pt-online-schema-change \ --alter "ADD INDEX idx_xxx (col1, col2)" \ --execute \ --max-load Threads_running=50 \ --critical-load Threads_running=100 \ D=mydb,t=mytable
4.1.3 查询优化检查清单
在优化 SQL 之前,按这个清单逐项检查:
-
是否有必要查询这么多数据?能否加 LIMIT? -
是否可以用覆盖索引避免回表? -
WHERE 条件是否命中索引?有没有索引失效的写法? -
JOIN 的顺序是否合理?小表驱动大表了吗? -
ORDER BY 和 GROUP BY 能否利用索引? -
子查询能否改写成 JOIN? -
是否有 OR 条件导致索引失效?能否改写成 UNION?
4.2 注意事项
4.2.1 生产环境操作警告
警告:以下操作可能影响业务,需谨慎!
-
不要在高峰期直接 ALTER TABLE 加索引,会锁表 -
不要随意 KILL 长时间运行的查询,可能导致数据不一致 -
开启 profiling 会有额外开销,分析完记得关闭 -
EXPLAIN ANALYZE 会实际执行 SQL,对大表查询要小心
4.2.2 常见错误
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4.2.3 常见索引失效场景
-- 1. 对索引字段使用函数
WHERE YEAR(create_time) = 2024 -- 失效
WHERE create_time >= '2024-01-01' -- 有效
-- 2. 隐式类型转换
WHERE phone = 13800138000 -- phone 是 varchar,失效
WHERE phone = '13800138000' -- 有效
-- 3. LIKE 左模糊
WHERE name LIKE '%张' -- 失效
WHERE name LIKE '张%' -- 有效
-- 4. OR 条件(除非所有条件都有索引)
WHERE user_id = 1 OR name = 'xxx' -- 如果 name 没索引则失效
WHERE user_id = 1 UNION SELECT ... WHERE name = 'xxx' -- 改写后都能用索引
-- 5. 不等于条件
WHERE status != 'deleted' -- 可能不走索引
WHERE status IN ('active', 'pending') -- 明确列出有效值
-- 6. IS NULL / IS NOT NULL(取决于优化器判断)
WHERE deleted_at IS NULL -- 可能不走索引
-- 7. 联合索引不满足最左前缀
-- 索引 (a, b, c)
WHERE b = 1 AND c = 2 -- 失效,必须从 a 开始
五、故障排查和监控
5.1 常见问题排查
5.1.1 查询突然变慢
之前一直很快的查询突然变慢,可能原因:
-- 1. 检查表的统计信息是否过期
SHOW TABLE STATUS LIKE 'orders'\G
-- 关注 Rows 和实际行数是否差异大
-- 重新分析表统计信息
ANALYZE TABLE orders;
-- 2. 检查是否有锁等待
SELECT * FROM information_schema.innodb_lock_waits;
SELECT * FROM sys.innodb_lock_waits;
-- 3. 检查缓冲池命中率
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
-- Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests 应该很低
-- 4. 检查是否有大事务
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started;
5.1.2 死锁排查
-- 查看最近的死锁信息
SHOW ENGINE INNODB STATUS\G
-- 找 LATEST DETECTED DEADLOCK 部分
-- 查看当前锁情况
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;
-- 如果需要 KILL 阻塞的事务
-- 先确认事务 ID
SELECT * FROM information_schema.innodb_trx;
-- 然后 KILL 对应的线程
KILL <thread_id>;
5.1.3 连接数耗尽
-- 查看连接数配置和使用情况
SHOW VARIABLES LIKE 'max_connections';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
-- 查看各用户/主机的连接数
SELECT user, host, COUNT(*) AS conn_count
FROM information_schema.processlist
GROUP BY user, host
ORDER BY conn_count DESC;
-- 查看连接在执行什么
SELECT * FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;
5.2 监控配置
5.2.1 Prometheus + Grafana 监控
# mysqld_exporter 采集配置
# prometheus.yml
scrape_configs:
- job_name: 'mysql'
static_configs:
- targets: ['mysql-server:9104']
relabel_configs:
- source_labels: [__address__]
target_label: instance
5.2.2 关键监控指标
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5.2.3 告警规则示例
# Prometheus 告警规则
groups:
- name: mysql_alerts
rules:
- alert: MySQLSlowQueries
expr: rate(mysql_global_status_slow_queries[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL 慢查询过多"
description: "实例 {{ $labels.instance }} 每分钟慢查询 {{ $value }} 次"
- alert: MySQLHighConnections
expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections > 0.85
for: 5m
labels:
severity: critical
annotations:
summary: "MySQL 连接数过高"
description: "实例 {{ $labels.instance }} 连接数使用率 {{ $value | humanizePercentage }}"
- alert: MySQLReplicationLag
expr: mysql_slave_status_seconds_behind_master > 30
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL 主从延迟过大"
description: "从库 {{ $labels.instance }} 延迟 {{ $value }} 秒"
六、总结
6.1 技术要点回顾
-
定位先行:先用 pt-query-digest 找出 TOP N 慢查询,不要盲目优化 -
理解执行计划:EXPLAIN 是优化的基础,要能看懂每个字段的含义 -
索引设计有原则:最左前缀、区分度、覆盖索引,不是随便加 -
验证优化效果:优化前后要有数据对比,不能凭感觉
6.2 进阶学习方向
-
MySQL 内部原理 -
学习资源:《高性能 MySQL》第四版、《MySQL 技术内幕:InnoDB 存储引擎》 -
实践建议:理解 B+ 树索引结构、MVCC、锁机制
-
-
查询优化器 -
学习资源:MySQL 官方文档 – Optimization -
实践建议:学习使用 optimizer_trace 分析优化器决策过程
-
-
分布式数据库 -
学习资源:TiDB、CockroachDB 等 NewSQL 数据库 -
实践建议:了解分布式场景下的查询优化差异
-
6.3 参考资料
-
MySQL 官方优化文档 – 权威参考 -
Percona Toolkit 文档 – pt-query-digest 等工具使用指南 -
Use The Index, Luke – SQL 索引原理讲解 -
MySQL Performance Blog – Percona 技术博客
附录
A. 命令速查表
-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
-- 查看执行计划
EXPLAIN SELECT ...;
EXPLAIN FORMAT=JSON SELECT ...;
EXPLAIN ANALYZE SELECT ...;
-- 查看表索引
SHOW INDEX FROM table_name;
-- 查看表结构
SHOW CREATE TABLE table_name\G
-- 分析表统计信息
ANALYZE TABLE table_name;
-- 查看当前执行的查询
SHOW PROCESSLIST;
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G
-- 开启 profiling
SET profiling = 1;
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;
B. EXPLAIN type 详解
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C. 术语表
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
想了解更多干货,可通过下方扫码关注

可扫码添加上智启元官方客服微信👇

17认证网








