mysql 8.0并行查询仅对无索引、无聚合、无limit的全表扫描有效,需同时开启parallel_query、设置parallel_threads_limit和innodb_parallel_read_threads,且必须用explain format=tree验证parallel scan。

MySQL 8.0 的并行查询不是“开了就快”的通用加速器,它只对极少数无索引、无聚合、无 LIMIT 的全表扫描生效,且默认完全关闭。盲目调参或期待自动并行,大概率白忙一场。
EXPLAIN FORMAT=TREE 看不到 Parallel scan,说明并行根本没启用
普通 EXPLAIN 或 EXPLAIN FORMAT=JSON 完全不显示并行信息。唯一可靠验证方式是:EXPLAIN FORMAT=TREE SELECT ...,然后检查输出第一行是否为 -> Parallel scan on table_name。
常见失效原因包括:
- WHERE 条件命中了任何索引(哪怕只是部分命中),就会退化为
-> Table scan on table_name或-> Index range scan on table_name - 语句含
LIMIT、ORDER BY、GROUP BY、DISTINCT、子查询、窗口函数——这些直接让优化器跳过并行路径 - 表太小(例如
rows ),优化器判定“不值得并行”,静默降级 - 事务隔离级别为
REPEATABLE READ且存在 gap lock,InnoDB 内部会禁用并行以保证 MVCC 一致性
三个参数必须同时设对,缺一不可
MySQL 8.0.30+ 的原生并行查询是实验性功能,需显式开启三要素:
-
SET GLOBAL parallel_query = ON:全局开关,默认OFF -
SET GLOBAL parallel_threads_limit = 3:单查询最多用几个线程(含主线程),建议 2–4;设成 CPU 核数会因调度开销拖慢 -
SET GLOBAL innodb_parallel_read_threads = 2:InnoDB 层并行读线程数,必须 ≥parallel_threads_limit - 1
注意:innodb_parallel_read_threads 单独设为 4 是无效的——没有 parallel_query = ON,它只影响极少数底层物理读场景,和用户 SQL 并行无关。
并行只加速 I/O 扫描,不解决其他瓶颈
并行扫描发生在 InnoDB 存储引擎层,仅分摊数据页读取(Handler_read_rnd_next)耗时。以下情况并行几乎无效:
- 查询已走覆盖索引(
Extra: Using index),根本不触发磁盘/缓冲池页读 - 瓶颈在临时表写磁盘(
Using temporary; Using filesort)或网络传输 - 高并发下多查询争抢同一张宽表的 B+ 树页锁(
dict_index_wait_for_x_lock),并行线程排队等待 - CPU 已满载或 buffer pool mutex 竞争高,加线程反而加剧锁争用
实测中,SSD 场景下 innodb_parallel_read_threads > 16 基本无收益;HDD 下设 2–4 就是上限。
确认真正在并行运行,别信 CPU 使用率或执行时间
CPU 升高 ≠ 并行生效,可能是锁等待导致线程堆积。真正验证方法只有两个:
- 查
performance_schema.threads:执行查询时运行SELECT THREAD_ID, PROCESSLIST_INFO FROM performance_schema.threads WHERE PROCESSLIST_INFO LIKE '%SELECT%',看到多个状态为query exec(非connect或sleep)的线程才算数 - 看
EXPLAIN ANALYZE输出:搜索"parallel_workers": N和"rows_examined_per_worker"字段,N > 1 且各 worker 行数接近总扫描量 / N,才表示数据被实际分片
最容易被忽略的是:即使 EXPLAIN FORMAT=TREE 显示 Parallel scan,只要表上有未提交的写事务(哪怕另一会话刚 INSERT 了一行没 COMMIT),InnoDB 也会静默退化为单线程扫描,且不报错、不提示。











