前言
很多开发者在实际项目中都会碰到类似问题:单独执行某条 SQL 时速度很快,但一旦进入压测阶段、并发请求上来后,接口响应明显变慢,数据库 CPU 持续飙高,连接数不断增加,甚至还会出现查询超时。

不少人第一反应是先优化 SQL,但仅仅优化语句本身,往往只能解决部分性能问题。MySQL 的高并发查询承载能力,本质上由SQL 索引、事务锁机制、内核参数、缓存体系以及整体架构设计共同决定。
本文基于 InnoDB 引擎(适用于 MySQL 5.7 / 8.0 主流生产环境),从基础原理到实战手段,系统梳理一套可直接落地的优化方案,帮助业务系统支撑更高的并发查询流量。
一、先理解:InnoDB 高并发基础原理
InnoDB 能够支撑高并发读写,主要依赖两大核心机制:
- MVCC 多版本并发控制:普通 SELECT 属于快照读,可实现无锁查询。也就是说,读不会阻塞读,读通常也不会阻塞写,这是 MySQL 支撑大量查询请求的关键基础。
- 行级锁:在正常情况下,InnoDB 只锁定被修改的数据行,锁粒度更小。相较于 MyISAM 的表级锁,写入并发能力会有明显提升。
需要特别注意的是:MVCC 和行锁只是高并发的底层保障,如果使用方式不当,依然可能出现大量阻塞、吞吐能力上不去的问题。
常见的并发瓶颈包括:慢 SQL 长时间占用工作线程、索引失效导致大范围扫描、长事务长期持有锁、热点行竞争严重,以及大量重复查询直接把数据库打满。
二、第一层优化:SQL & 索引优化(投入产出比最高)
高并发场景下有一条非常重要的原则:单条查询耗时越短,系统可承载的并发量越高。查询执行时间越长,数据库连接占用时间越久,连接池资源就越容易被快速耗尽。
2.1 高频查询必须命中有效索引
高频业务 SQL 一定要避免全表扫描,这是 MySQL 并发性能优化的基本前提。
- 避免对索引字段进行函数运算或发生隐式类型转换;
- 模糊查询尽量不要使用前置通配符
%关键词; - 多条件查询应合理设计联合索引,并遵循最左匹配原则。
示例业务场景:
-- 筛选条件 status + verify_idf_idWHERE status = 1 AND verify_idf_id = 'xxx'
创建联合索引:
CREATE INDEX idx_status_verify ON openapi_price(status, verify_idf_id);
2.2 禁止SELECT *
查询时只返回业务真正需要的字段,主要收益包括:
- 减少回表 IO 开销;
- 降低网络传输的数据量;
- 更容易命中覆盖索引,减少访问主键数据页的次数。
2.3 IN、分页、排序的坑点
IN (常量列表):少量参数时通常可以走 range 索引;如果 IN 中元素过多,优化器可能放弃索引,建议拆分为分批查询;IN(子查询):MySQL 8.0 内部会自动进行半连接优化,而在 5.7 环境中,优先使用EXISTS往往更稳定;ORDER BY不要对索引列做函数转换,例如CAST(str_id AS UNSIGNED)。这种写法会直接导致索引失效,并触发 filesort 文件排序,在高并发查询场景下压力非常大;必要时可以把排序逻辑上移到应用层内存中处理。- 大分页
limit offset,size会随着 offset 的增大而持续变慢,建议改为基于主键的分页方案。
2.4 及时清理无效慢查询
长期存在的慢查询会持续占用 MySQL 工作线程,并发流量一旦涌入,就很容易形成请求堆积。线上环境应持续监控慢查询日志,并定期进行分析和优化。
三、第二层优化:事务与锁优化,减少查询阻塞
很多时候,查询卡顿并不是因为查询语句本身慢,而是被写事务持有的锁阻塞了。
3.1 尽可能缩短事务执行时长
事务从开启到提交的时间越长,行锁持有时间就越久,其他读写请求出现锁等待的概率也会更高。
- 不要在事务内部执行耗时的网络请求或大量查询;
- 事务中只保留必要的 DML 操作;
- 避免长事务长时间不提交。
3.2 区分快照读与当前读
普通 SELECT 属于快照读,默认不加锁;
如果业务并不需要强一致性,就不要随意使用 SELECT ... FOR UPDATE 这类锁定读。大量锁定读会造成明显的锁竞争,严重影响 MySQL 高并发性能。
3.3 规避热点行更新
大量并发请求同时更新同一行数据时,通常会形成串行等待,系统吞吐能力会快速下降。
常见优化方案包括:在业务层做请求合并、异步处理,或通过数据分片分散热点竞争。
四、第三层优化:MySQL内核参数调优
MySQL 参数优化必须结合服务器内存、CPU、磁盘等资源情况综合评估,不要直接照搬网络上的通用模板。
核心关键参数
innodb_buffer_pool_size:这是 InnoDB 中最重要的参数之一,主要用于缓存索引页和数据页。通常建议设置为物理内存的 50%~70%;只要缓冲池足够大,磁盘 IO 压力就会明显下降,MySQL 查询并发能力也会随之提升。
max_connections:最大连接数,默认值通常偏小。但也不能设置得过大,否则连接过多会带来更高的操作系统上下文切换开销。一般业务场景可设置在 500~2000,并与应用侧连接池配合使用。
innodb_read_io_threads / innodb_write_io_threads:用于控制读写 IO 线程数量,可提升磁盘并发读写能力,在多核服务器上可以根据实际情况适当调高。
innodb_flush_log_at_trx_commit:这是数据安全与性能之间的重要平衡参数:
- 每次事务提交都刷盘,安全性最高,但性能相对最低;
- 每秒刷一次磁盘,系统崩溃时可能丢失 1 秒数据,但查询和写入的并发性能会有明显提升。
生产环境调整前,一定要先评估数据丢失风险。
sort_buffer_size、join_buffer_size 这两个参数,不建议直接在全局范围内一次性调得很大。原因很简单:如果设置过高,内存会被快速消耗。尤其在排序和关联查询较多的系统里,更应该优先结合真实业务场景优化 SQL,而不是盲目依赖增大缓冲区,这通常比单纯调参更有效。
五、第四层优化:引入缓存,降低数据库查询压力
数据库的并发承载能力始终存在上限,最有效的优化方式之一,就是减少真正落到 MySQL 的请求数量。
5.1 应用层缓存(Redis)
对于更新频率低、查询频率高的基础数据、系统配置、数据字典、接口文档等信息,可以将查询结果缓存到 Redis 中。
让大部分流量优先命中缓存,能够显著减少对数据库的高频访问。
5.2 合理使用查询缓存
MySQL 8.0 已经移除了 Query Cache,因此不要再依赖它;而在 MySQL 5.7 中也通常不建议开启,因为频繁更新的表会导致缓存频繁整体失效。
5.3 本地内存缓存
对于热点静态数据,还可以直接缓存在应用进程内存中,进一步减少跨网络访问缓存服务的开销。
六、第五层优化:架构层面横向扩容
单台 MySQL 无论怎样优化,都无法突破硬件资源上限。当业务流量持续增长时,就需要从数据库架构层面进行升级。
读写分离:通过一主多从架构,将大部分查询请求路由到从库,主库专注写入,从而分担主库查询压力。
需要注意:从库通常存在一定的数据同步延迟,强一致性要求高的业务查询仍然应访问主库。
分库分表:当单表数据量达到千万级后,索引维护成本和查询性能都会持续下滑。此时可按业务维度进行分片,分散单表查询压力,提升整体并发吞吐能力。
业务隔离:核心业务与非核心业务使用独立数据库实例,避免报表、导出等非核心任务抢占核心查询资源。
七、线上排查并发性能问题的手段
当遇到 MySQL 并发查询变慢或接口卡顿时,可以按以下顺序进行排查:
show processlist查看是否存在大量长时间执行的 SQL、锁等待或阻塞会话;explain验证高频查询是否正确命中索引;- 重点观察监控指标:CPU 使用率、磁盘 IO、连接数、锁等待时长、慢查询数量;
- 查看
innodb_status,分析行锁等待和事务状态; - 核对缓冲池命中率,判断是否存在大量磁盘读取导致的性能瓶颈。
八、总结
提升 MySQL 并发查询能力,通常可以按照以下优先级逐步落地:
- 优先优化 SQL 与索引,尽可能缩短单条查询耗时(最高优先级);
- 规范事务使用方式,减少锁竞争和阻塞;
- 合理调整 InnoDB 核心参数,充分利用服务器硬件资源;
- 引入多级缓存,减少直接访问数据库的请求量;
- 当流量持续增长时,通过读写分离、分库分表等方式完成架构扩容。
MySQL 高并发优化并不存在所谓的万能配置,所有优化动作都必须结合真实业务流量和数据特征持续观察、持续调整。建议先把基础 SQL 质量和索引设计做好,再考虑架构扩容,避免只靠加机器来治标不治本。
