You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么MySQL子查询中的OR会大幅降低查询性能?附优化案例解析

性能差异核心原因

你遇到的性能差异本质是JOIN条件中的OR语句触发了MySQL的全表扫描回退机制,拆分两个LEFT JOIN加COALESCE的写法可以完全命中联合索引,避免了千万级数据的全表遍历。


执行计划差异解读

原始慢查询执行计划问题点

看financial_transactions(ft)表对应的执行计划行:

  • type字段值为ALL:代表对千万级(12587878行)的ft表做全表扫描,这是耗时高的核心来源
  • Extra字段值为Range checked for each record (index map: 0x2):意味着MySQL无法直接使用你建的transactions_unique_by_commercial_doc联合索引做JOIN匹配,只能为前面关联得到的每一行结果,单独到ft表做一次范围检查,相当于关联N行就要在千万级表上扫N次,效率极低

你单独执行子查询速度快,是因为子查询单独执行时优化器会优先过滤ft表的数据再做关联,但子查询和外层表关联时,优化器选择了嵌套循环关联顺序,导致ft表需要逐行匹配外层数据,性能就会指数级下降。

优化后查询执行计划优势

看ft_one、ft_two对应的执行计划行:

  • 两个表的type字段值都是ref:代表两次关联都命中了transactions_unique_by_commercial_doc联合索引,每次关联仅需查询1行数据
  • 无全表扫描操作,所有关联步骤都走索引匹配,千万级ft表不需要做全量遍历,耗时自然大幅下降

优化逻辑原理

你使用的拆分方案是处理JOIN条件OR性能问题的标准方案:

  1. 把JOIN ft ON (条件A) OR (条件B)拆为两次独立的LEFT JOIN:LEFT JOIN ft_one ON 条件A、LEFT JOIN ft_two ON 条件B,两次关联的条件都可以独立匹配联合索引,不会出现索引失效问题
  2. 用COALESCE(ft_one.conversion_rate, ft_two.conversion_rate)取非空的转换率,和原始OR逻辑完全等价:只要任意一个条件匹配就取对应值,两个都未匹配则返回NULL,完全符合原有业务逻辑

另外原始查询存在一个隐形逻辑问题:你对ft表声明了LEFT JOIN,但WHERE条件中加了ft.company_id = 14792,相当于把LEFT JOIN转为了INNER JOIN,无匹配的行都会被过滤。优化后你把company_id条件移到了LEFT JOIN的关联条件中,更符合LEFT JOIN语义,如果业务需要过滤掉无转换率的行,只需要在子查询WHERE中加coalesce(ft_one.conversion_rate, ft_two.conversion_rate) IS NOT NULL即可,不会影响性能。


内容的提问来源于stack exchange,提问作者user2320239

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 21:27:03