线上问题排查记录——MySQL 子查询报错 “Subquery returns more than 1 row” 问题总结

问题描述

在执行一个包含多个 UNION ALL 的复杂查询时,报错:

复制代码
Subquery returns more than 1 row

该查询的核心是多个标量子查询(correlated subquery)用于从字典表 zz_global_dict_item 中取 item_name

sql 复制代码
(SELECT d.item_name FROM zz_global_dict_item d 
 WHERE d.dict_code = 'xxx' AND d.item_id = 主表.字段)

排查过程与发现

  1. 数据重复检查

    执行以下查询均无结果:

    sql 复制代码
    SELECT dict_code, item_id, COUNT(*) 
    FROM zz_global_dict_item 
    GROUP BY dict_code, item_id 
    HAVING COUNT(*) > 1;

    (dict_code, item_id) 组合唯一,无重复。

  2. 不可见字符检查

    sql 复制代码
    SELECT ... WHERE LENGTH(item_id) != CHAR_LENGTH(item_id);

    → 无结果,无隐藏字符(如全角空格、控制字符)。

  3. 空值/NULL 检查

    主表和字典表中空值情况正常,未导致多行匹配。

  4. 拆分查询验证

    将大查询拆成 6 个独立部分(领用、归还、报废、新增、合并等),每个部分单独执行均正常,子查询只返回 0 或 1 行。

  5. 加 LIMIT 1 测试

    在所有子查询中加 LIMIT 1 后,整个 UNION ALL 查询正常执行,不再报错。

根本原因

MySQL 优化器 Bug / 执行计划异常

  • 每个子查询单独运行时都只返回最多 1 行。
  • 但当多个标量子查询放在同一个大 UNION ALL 查询中时,MySQL 优化器在解析执行计划阶段误判某些子查询可能返回多行,从而提前抛出 "Subquery returns more than 1 row" 错误(即使实际运行不会)。
  • 这属于 MySQL(尤其是 5.7/8.0 某些版本)在复杂 UNION + 标量子查询场景下的已知边缘问题。
  • LIMIT 1 后,优化器明确知道子查询最多返回一行,于是跳过错误检查,查询正常执行。

解决方案

方案1:短期快速修复(推荐立即使用)

在所有标量子查询中加入以下内容:

sql 复制代码
AND d.deleted_flag = 0
ORDER BY d.show_order ASC
LIMIT 1
  • deleted_flag = 0:避免匹配到历史已删除的垃圾数据
  • ORDER BY show_order:确保取到显示顺序正确的记录
  • LIMIT 1:彻底规避优化器误判报错

已验证有效,且结果准确。

方案2:长期最佳实践(强烈推荐)

将所有标量子查询改为 LEFT JOIN

彻底消除子查询,避免优化器问题,同时大幅提升性能。

示例结构(简化):

sql 复制代码
SELECT ...
    d1.item_name AS `来源`,
    ...
FROM biz_receipt_detail brd
LEFT JOIN zz_global_dict_item d1 
  ON d1.dict_code = 'DictReceiptType' 
  AND d1.item_id = brd.receipt_source
  AND d1.deleted_flag = 0
...

方案3:其他临时规避(不推荐长期)

  • 会话级设置:SET optimizer_switch = 'derived_merge=off';
  • SET SQL_BIG_SELECTS = 1;

结论

  • 这不是数据问题,而是 MySQL 优化器在复杂 UNION ALL + 标量子查询下的边缘 Bug
  • LIMIT 1(配合 deleted_flagORDER BY)是安全、有效的解决方案,已验证可用。
  • 建议后续重构为 LEFT JOIN 方式,彻底根治并提升性能。
相关推荐
Coder_Boy_2 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
helloworldandy2 小时前
使用Pandas进行数据分析:从数据清洗到可视化
jvm·数据库·python
数据知道4 小时前
PostgreSQL 故障排查:如何找出数据库中最耗时的 SQL 语句
数据库·sql·postgresql
qq_12498707534 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
枷锁—sha4 小时前
【SRC】SQL注入WAF 绕过应对策略(二)
网络·数据库·python·sql·安全·网络安全
Coder_Boy_4 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
Gain_chance4 小时前
35-学习笔记尚硅谷数仓搭建-DWS层最近n日汇总表及历史至今汇总表建表语句
数据库·数据仓库·hive·笔记·学习
此生只爱蛋4 小时前
【Redis】主从复制
数据库·redis
马猴烧酒.5 小时前
【面试八股|JAVA多线程】JAVA多线程常考面试题详解
java·服务器·数据库
天天爱吃肉82185 小时前
跟着创意天才周杰伦学新能源汽车研发测试!3年从工程师到领域专家的成长秘籍!
数据库·python·算法·分类·汽车