MySQL 8.0性能调优实战:慢查询分析与索引优化全流程

MySQL性能调优慢查询分析开始

MySQL性能问题80%源于慢查询和索引设计缺陷。调优的第一步不是改参数,而是找到真正慢在哪里。慢查询日志是MySQL性能诊断最可靠的数据源,用事实而非猜测驱动优化。

开启慢查询日志并设置合理阈值:

-- my.cnf 配置
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5    # 超过0.5秒记录
log_queries_not_using_indexes = 1  # 未用索引的查询也记录
min_examined_row_limit = 100       # 扫描行数少于100不记录

-- 运行时动态调整
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;

long_query_time设为0.5秒而非默认的10秒——生产环境中0.5秒的查询已经影响用户体验。log_queries_not_using_indexes=1确保全表扫描的查询不遗漏。

用EXPLAIN分析执行计划

拿到慢查询后,用EXPLAIN看执行计划:

EXPLAIN SELECT o.order_id, o.amount, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.create_time BETWEEN '2026-07-01' AND '2026-07-30'
  AND o.status = 'PAID'
  AND c.region = 'EAST'
ORDER BY o.amount DESC
LIMIT 50;

EXPLAIN输出需要重点关注五列:

| 列名 | 关注点 | 危险信号 |
|——|——–|———-|
| type | 访问类型 | ALL(全表扫描)、index(全索引扫描) |
| key | 实际使用的索引 | NULL(未用索引) |
| rows | 预估扫描行数 | 远大于实际返回行数 |
| filtered | 过滤比例 | 低于10%说明大量无效扫描 |
| Extra | 附加信息 | Using filesort、Using temporary |

type列从好到差:system > const > eq_ref > ref > range > index > ALL。生产查询至少要达到range级别。

上面的查询如果customer_id和create_time没有联合索引,大概率会走ALL扫描。下面看索引优化如何解决这个问题。

索引设计原则与联合索引优化

索引设计遵循最左前缀原则。联合索引(a, b, c)可以覆盖a、(a,b)、(a,b,c)三种查询,但不能覆盖(b,c)查询:

-- 为上面的查询创建联合索引
-- 订单表:status + create_time 联合索引
CREATE INDEX idx_orders_status_createtime
ON orders(status, create_time);

-- 客户表:region索引
CREATE INDEX idx_customers_region
ON customers(region);

-- 订单明细表:order_id索引
CREATE INDEX idx_orderitems_orderid
ON order_items(order_id);

联合索引列顺序的选择原则:等值查询列在前,范围查询列在后。status是等值条件(= ‘PAID’),create_time是范围条件(BETWEEN),所以status在前。

验证索引效果:

EXPLAIN SELECT o.order_id, o.amount, c.customer_name
FROM orders o FORCE INDEX(idx_orders_status_createtime)
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.create_time BETWEEN '2026-07-01' AND '2026-07-30'
  AND o.status = 'PAID'
  AND c.region = 'EAST'
ORDER BY o.amount DESC
LIMIT 50;

优化后type从ALL变为range,扫描行数从全表降到目标范围内的行数。

覆盖索引消除回表查询

当查询的所有列都包含在索引中时,InnoDB直接从索引返回数据,不需要回表查主键索引:

-- 查询只需要order_id, status, amount三列
SELECT order_id, status, amount
FROM orders
WHERE status = 'PAID' AND create_time BETWEEN '2026-07-01' AND '2026-07-30';

-- 创建覆盖索引
CREATE INDEX idx_orders_cover
ON orders(status, create_time, order_id, amount);

覆盖索引的代价是索引体积增大和写入性能下降。每增加一个索引列,INSERT/UPDATE/DELETE都需要额外维护索引。评估覆盖索引收益时对比:

-- 对比回表和覆盖索引的行扫描量
-- 回表查询
EXPLAIN SELECT order_id, status, amount, customer_id, remark
FROM orders WHERE status = 'PAID' AND create_time > '2026-07-01';

-- 覆盖索引查询
EXPLAIN SELECT order_id, status, amount
FROM orders WHERE status = 'PAID' AND create_time > '2026-07-01';

Extra列出现Using index就是覆盖索引生效的标志。

参数调优与Buffer Pool配置

MySQL 8.0的关键内存参数:

[mysqld]
# InnoDB Buffer Pool - 设置为物理内存的60-70%
innodb_buffer_pool_size = 16G
# 多Buffer Pool实例减少竞争
innodb_buffer_pool_instances = 8

# 日志配置
innodb_log_file_size = 1G
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 1

# 并发配置
innodb_thread_concurrency = 0  # 0表示不限制,由InnoDB自行管理
innodb_read_io_threads = 8
innodb_write_io_threads = 8

# 查询缓存 - MySQL 8.0已移除,不需要配置

# 连接配置
max_connections = 500
wait_timeout = 600
interactive_timeout = 600

innodb_flush_log_at_trx_commit = 1是事务安全的最高级别,每次事务提交都刷盘。设为2时每秒刷盘一次,性能提升约10倍但有1秒数据丢失风险。金融场景必须用1。

慢查询实时监控方案

用Performance Schema替代慢查询日志做实时监控,开销更低:

-- 开启语句事件采集
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE 'statement/%';

-- 查询当前最慢的10条SQL
SELECT DIGEST_TEXT,
       COUNT_STAR as exec_count,
       ROUND(SUM_TIMER_WAIT / 1000000000000, 3) as total_time_sec,
       ROUND(AVG_TIMER_WAIT / 1000000000, 2) as avg_time_ms,
       SUM_ROWS_EXAMINED as rows_scanned,
       SUM_ROWS_SENT as rows_sent
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;

rows_scanned / rows_sent的比值反映查询效率——比值越大说明无效扫描越多。比值超过100的查询优先优化。

MySQL性能调优不是调完就结束的工作。业务数据增长、查询模式变化都会让之前的优化方案失效。建立慢查询巡检机制,定期用EXPLAIN验证关键查询的执行计划,才是持续保持数据库性能的方法。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql80-xing-neng-diao-you-shi-zhan-man-cha-xun-fen-xi-yu/

(0)
小编小编
上一篇 14小时前
下一篇 14小时前

相关推荐