You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

为何MySQL中相关标量子查询的执行速度比PostgreSQL慢约10倍?

为何MySQL中相关标量子查询的执行速度比PostgreSQL慢约10倍?

这个问题我之前也研究过类似的场景,结合你给出的执行计划和跨平台测试数据,咱们来拆解下为什么会有10倍左右的性能差距——核心其实是单次子查询的执行效率差了一个数量级,而不是执行次数的问题(两者都循环执行了3000次子查询)。

1. 单次子查询的行处理效率是核心差异

从执行计划的实际耗时就能直接看出来:

  • MySQL里每个子查询单次执行耗时约2.5ms(Windows环境)/1.8ms(Ubuntu),而PostgreSQL只有0.227ms/0.175ms,刚好差10倍左右。
  • 虽然两者都是做「全表扫描+过滤匹配行」,但底层处理逻辑的开销天差地别:
    • MySQL的InnoDB是聚簇索引组织表,全表扫描本质是遍历主键索引树,每行数据的访问需要经过索引节点的跳转,而且哪怕已经找到匹配的id,它也会完整遍历完3000行(执行计划里Table scan on t1rows=3000 loops=3000可以佐证);
    • PostgreSQL的堆表(默认存储引擎)全表扫描是直接访问磁盘上的堆文件,行数据的内存布局更紧凑,而且执行器在循环处理行时做了大量C层优化(比如循环展开、减少函数调用开销),哪怕同样处理3000行,单循环的CPU开销比MySQL小很多。

2. 子查询的执行上下文开销差异

MySQL把这个子查询标记为dependent subquery in projection,意味着每次执行子查询都要重新初始化完整的查询上下文:包括绑定变量、创建临时执行环境、初始化聚合函数等;而PostgreSQL的SubPlan 1作为重复执行的子计划,会复用部分执行上下文,减少了每次执行的初始化开销,进一步拉大了单次执行的效率差。

3. 默认配置下的执行器优化差异

两个数据库的默认配置也会影响这个场景的性能:

  • PostgreSQL对顺序扫描的CPU缓存友好性做了更多优化,比如预读更多数据到CPU缓存行,减少缓存 miss;而MySQL 8.0默认配置下,InnoDB的全表扫描可能没有充分利用CPU的缓存特性,行数据的序列化/反序列化开销更大。
  • 另外,PG的过滤逻辑(id = t2.id)是在内存中直接比较原始数据,而MySQL的InnoDB需要先把行数据从聚簇索引中读取出来,经过引擎层到执行器层的转换,额外增加了开销。

补充:关于优化器没有改写为JOIN的问题

你提到两个数据库都没有把标量子查询自动改写为JOIN,这是因为这种「投影列中的相关标量子查询」场景,优化器判断改写的收益不明确(或者说优化器规则没有覆盖这种场景),所以都选择了最直接的循环执行方式。但这不是性能差异的原因——核心还是单次子查询的执行效率差了10倍,累计到3000次就变成了总耗时的10倍差距。

最后再强调下:这种差异本质是两个数据库的执行器架构、存储引擎的行处理模型不同导致的,PostgreSQL在这种单循环、内存中行处理的场景下,底层优化更极致,而MySQL的InnoDB更侧重事务、聚簇索引的优势场景,在这种简单循环全表扫描的场景下就显得开销更大。

火山引擎 最新活动