mysql性能调优的基本原则与实践

13次阅读

索引需匹配查询条件而非越多越好。WHERE、JOIN、ORDER BY、GROUP BY才是索引生效场景;联合索引遵循最左前缀原则;避免在索引列上用函数操作。

mysql性能调优的基本原则与实践

索引不是越多越好,而是要匹配查询条件

很多开发者一听说“加索引能提速”,就给所有字段都加上 INDEX,结果反而拖慢写入、增大存储、让优化器选错执行计划。mysqlWHEREJOINORDER BYGROUP BY 才是索引真正起效的场景。

实操建议:

  • EXPLaiN 看查询是否命中索引,重点关注 type(最好是 refrange)、key(实际使用的索引名)、rows(扫描行数)
  • 联合索引要遵循最左前缀原则:INDEX(a, b, c) 能用于 WHERE a=1WHERE a=1 AND b=2,但不能用于 WHERE b=2
  • 避免在索引列上做函数操作,比如 WHERE YEAR(create_time) = 2024 会让索引失效;改用范围查询:WHERE create_time >= '2024-01-01' AND create_time
  • 区分 select * 和只查必要字段——宽表 + 覆盖索引(Extra 显示 using index)能显著减少回表开销

慢查询日志必须开,但不能只靠它“事后救火”

slow_query_log = ON 是调优起点,但光打开不够。默认 long_query_time = 10 秒,对线上服务来说早已太晚。真实业务中,响应超过 1 秒的查询就该被关注。

实操建议:

  • long_query_time 设为 0.5(单位秒),并开启 log_queries_not_using_indexes = ON,强制记录没走索引的查询
  • mysqldumpslowpt-query-digest 分析日志,优先处理 count 高、Avg_query_time 长、Rows_examined 大的 SQL
  • 注意:开启慢日志本身有 I/O 开销,生产环境建议用 log_output = table(写入 mysql.slow_log 表),再定时归档,避免影响磁盘性能

innodb_buffer_pool_size 不等于“越大越好”,得看物理内存和工作集

这个参数控制 InnoDB 缓存数据页和索引页的内存大小。设得太小,频繁磁盘读取;设得太大,可能挤占 OS 缓存或触发 swap,反而卡顿。

实操建议:

  • 通用经验公式:innodb_buffer_pool_size = 总内存 × 0.7 ~ 0.8,但前提是你的热数据(活跃访问的表+索引)能放进这个池子
  • 检查命中率:
    SELECT (1 - (SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'Innodb_buffer_pool_reads') / (SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'Innodb_buffer_pool_read_requests')) * 100 AS hit_rate;

    持续低于 95%,说明池子可能不够或查询不集中

  • 若实例混跑多个 MySQL 或其他服务(如 redis、java 应用),务必预留足够内存给 OS 和其他进程,否则 OOM killer 可能直接杀掉 mysqld

UPDATE/delete 不加 WHERE 条件或没走索引,是线上事故高发区

这类语句一旦没走索引,会锁全表(尤其在 RR 隔离级别下),阻塞后续所有 DML,甚至拖垮整个库。比慢查询更危险的是“静默慢更新”——没有报错,但锁了 10 分钟。

实操建议:

  • 上线前必须确认 EXPLAIN 结果中的 type 不是 ALL,且 rows 在可接受量级(比如几万以内)
  • 批量更新/删除分批做,加 LIMIT 并用主键范围控制,例如:
    DELETE FROM orders WHERE status = 'pending' AND id BETWEEN 10000 AND 20000;
  • 开发环境启用 sql_safe_updates = ON,强制要求 UPDATE/DELETE 必须带 WHERE 且含键值条件,避免误删
  • DDL 操作(如加索引)在大表上也等效于全表扫描+重建,务必在低峰期用 ALgoRITHM=INPLACE(5.6+)或工具pt-online-schema-change

实际调优中最容易被忽略的,是业务逻辑层的聚合压力——比如一个接口反复查同一张配置表几十次,或者用 SELECT * 拉回几百列却只用其中 2 列。数据库只是执行者,真正的瓶颈常常藏在应用怎么用它。

text=ZqhQzanResources