MySQL性能问题根源在架构不匹配业务增长,分库分表、读写分离等架构优化比调参和SQL优化更治本,盲目调参反而引发OOM或IO恶化。

架构瓶颈不解决,调参和SQL优化都是临时止痛
MySQL性能问题的根源往往不在SQL写得有多烂,而在于架构设计是否匹配业务增长节奏。单机扛不住读写压力时,强行调大 innodb_buffer_pool_size 或加索引,只会让磁盘IO更堵、锁争用更严重。
真实场景中,80%以上的“慢查询”在分库分表或读写分离落地后自然消失——不是SQL变快了,是流量被分流了。比如订单表按 user_id 拆分后,原来全表扫描的 SELECT * FROM orders WHERE user_id = ? 变成单分片查询,响应时间从2s降到20ms。
关键判断点:
• 单实例QPS持续超过3000且CPU长期>70%,该考虑读写分离
• 单表行数超5000万、日增100万+,分库分表需提上日程
• 写多读少且一致性要求不高(如日志类),优先上 MySQL + Kafka 异步落库,别硬扛
参数调优只对「已知瓶颈」生效,盲目改 max_connections 可能雪上加霜
MySQL参数不是越调越大越好。max_connections 设太高,每个连接占用内存叠加,可能触发OOM;sort_buffer_size 设太大,反而让小排序走磁盘临时文件(因为内存分配失败回退)。
真正要盯的参数只有几个:
• innodb_buffer_pool_size:设为物理内存的50%–75%,但必须留够OS缓存和MySQL其他线程空间
• innodb_log_file_size:太小导致频繁checkpoint,太大延长崩溃恢复时间,建议单个日志文件256M–1G
• tmp_table_size 和 max_heap_table_size:必须相等,否则内存临时表会悄悄转成磁盘临时表
查当前实际使用情况比看文档更重要:SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';
如果后者占前者的0.5%以上,说明buffer pool命中率不足
索引失效比没建索引更危险,LIKE '%abc' 和 OR 条件是高频雷区
很多慢查询不是因为没索引,而是SQL写法让已有索引完全失效。执行计划里出现 type: ALL 或 key: NULL 就是明确信号。
典型失效场景:
• WHERE name LIKE '%张':左模糊无法用B+树索引,改成 WHERE name LIKE '张%' 才有效
• WHERE a = 1 OR b = 2:即使a、b都有索引,MySQL 5.7默认不走索引(8.0+才支持index merge)
• WHERE status + 0 = 1:隐式类型转换导致索引失效,直接写 status = 1
• ORDER BY create_time DESC LIMIT 10:没覆盖索引时,可能触发filesort,加联合索引 (create_time, id) 更稳
验证方式永远是 EXPLAIN FORMAT=TRADITIONAL,别信“应该能走索引”这种猜测
SQL调优本质是减少数据搬运量,SELECT * 和子查询嵌套是最大成本黑洞
一条SQL慢,90%是因为它捞了太多不需要的数据。网络传输、内存拷贝、客户端解析全在拖后腿。
实操底线:
• 禁用 SELECT *,哪怕只少取2个字段,结果集体积可能缩小40%(尤其含TEXT/BLOB)
• 避免3层以上子查询,改用 JOIN 或临时表;MySQL对子查询优化能力弱,常生成派生表(type: DERIVED)
• 分页慎用 LIMIT 1000000, 20:偏移量越大,MySQL越要扫描前面所有行,改用游标分页(WHERE id > last_id ORDER BY id LIMIT 20)
• GROUP BY 前先用 WHERE 过滤,别指望MySQL自动优化执行顺序
最简单的提速动作:在应用层加 log_slow_queries = ON + long_query_time = 1,每周抓出TOP 10慢SQL,逐条用 EXPLAIN 和 SHOW PROFILE 定位卡点
真正的难点从来不在“怎么加索引”或“哪个参数该调多少”,而在于分清:这是数据库的问题,还是业务模型本身在制造压力。比如高频更新同一行的计数器字段,再怎么优化索引和事务隔离级别,都比不上把计数逻辑移到Redis里做原子累加。



















