mysql 8.0并行查询仅对满足全部硬性条件的无索引、无聚合、无limit全表扫描生效,需同时开启parallel_query、parallel_threads_limit和innodb_parallel_read_threads,并用explain format=tree验证“parallel scan”及explain analyze确认“parallel_workers”>1。

MySQL 8.0 的并行查询不是“设个参数就自动变快”的通用功能,它只对极少数无索引、无聚合、无 LIMIT 的全表扫描生效,且默认完全关闭。盲目开启或调高线程数,大概率没效果,甚至拖慢查询。
如何确认你的 SELECT 真的能走 Parallel scan
并行扫描只在满足全部硬性条件时才可能触发,缺一不可:
- 目标表是普通 InnoDB 表(非分区表、非临时表、非 MyISAM/Memory)
- 执行计划最外层必须是全表扫描(
type=ALL),且 WHERE 条件无法命中任何索引(例如WHERE status = 'ERROR',而status列确实没有索引) - 语句不含
LIMIT、ORDER BY、GROUP BY、DISTINCT、子查询、CTE、窗口函数 - 不走覆盖索引(
Extra不能出现Using index)——因为并行只加速物理页读取,不加速索引遍历 - 数据量足够大(通常 > 百万行),且未被
innodb_buffer_pool_size完全缓存
常见误判:看到 EXPLAIN FORMAT=JSON 里有 "parallel_table_scan": true,但实际执行仍是单线程;或者 SHOW VARIABLES LIKE 'innodb_parallel_read_threads' 返回 4,却对 SELECT * FROM t WHERE id = 123 这类索引查找毫无作用。
必须同时设置的三个参数,少一个都不行
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 并行无关。
验证是否真正在并行,别信 EXPLAIN 或执行时间
普通 EXPLAIN 或 EXPLAIN FORMAT=JSON 完全不显示并行信息。唯一可信验证方式只有两个:
- 运行
EXPLAIN FORMAT=TREE SELECT ...,检查输出第一行是否为-> Parallel scan on table_name;若出现-> Table scan on table_name或-> Index range scan on table_name,说明并行根本没启用 - 运行
EXPLAIN ANALYZE SELECT ...,搜索输出中是否含"parallel_workers": N(N > 1)和"rows_examined_per_worker"字段;若各 worker 扫描行数接近总扫描量 / N,则并行已生效 - 查
performance_schema.threads:执行查询时运行SELECT THREAD_ID, PROCESSLIST_INFO FROM performance_schema.threads WHERE PROCESSLIST_INFO LIKE '%SELECT%',观察是否出现多个query exec类型线程(非connect或sleep)
光看 CPU 使用率飙升或执行时间变短,不能说明并行在工作——可能是 buffer pool 缓存命中、I/O 调度优化或其他干扰因素。
为什么设了参数还是慢?关键瓶颈常被忽略
并行只加速 InnoDB 层的物理页读取(Handler_read_rnd_next),不解决其他环节:
- 如果查询已走覆盖索引(
Extra: Using index),根本不触发磁盘/缓冲池页读,innodb_parallel_read_threads完全无效 - 瓶颈在临时表写磁盘(
Using temporary; Using filesort)或网络传输,并行读毫无意义 - 高并发下多查询争抢同一张宽表的 B+ 树页锁(
dict_index_wait_for_x_lock),并行线程排队等待 - CPU 已满载或
buffer pool mutex竞争高,加线程反而加剧锁争用 - 主键很大(如 UUID),每页存的记录数少,导致扫描页数暴增,并行带来的 I/O 分摊收益被抵消
真正容易被忽略的一点:并行扫描发生在存储引擎内部,执行器只做轻量合并。这意味着即使并行启动了,COUNT(*) 的最终汇总、ORDER BY 的排序、GROUP BY 的分组,仍由主线程串行完成——这些阶段可能比扫描本身还慢。











