因为一条LEFT JOIN,差点把客户的数据搞丢了

因为一条LEFT JOIN,差点把客户的数据搞丢了

去年接了个迁移的活,从MySQL换到金仓。

代码改完,数据导完,测试跑了一遍,没问题。上线那天业务方看了一眼报表,说不对,少了十几条。

我赶紧查。发现有个SQL是这样写的:

sql 复制代码
SELECT * 
FROM t1 LEFT JOIN t2 
ON t1.id1 = t2.id2 
WHERE t2.name2 = 'cc';

业务方说这个报表要统计所有用户,没下过单的也要显示"暂无订单"。左表是用户表,右表是订单表。用LEFT JOIN,没订单的用户应该保留,订单字段填空。

结果那十几条没订单的用户,全没了。

查了半天执行计划,才发现金仓的优化器把LEFT JOIN自动转成了INNER JOIN。

当时我就想,凭什么替我做这个决定?

后来理了一遍SQL的执行顺序才明白:先做JOIN,再用WHERE过滤。LEFT JOIN产生的NULL行,碰到WHERE条件t2.name2 = 'cc',NULL等于'cc'是false,就被扔掉了。

优化器一看,反正你LEFT JOIN产生的NULL行最后都会被干掉,那我直接帮你换成INNER JOIN,效率还高。

逻辑上说得通,但业务语义变了。

这种写法其实挺常见的,我翻了一下代码,类似的还有:

sql 复制代码
SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.status = 1;
SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.amount > 100;

只要WHERE条件里有右表的非空列,优化器就可能动手脚。

那什么情况下不会触发?

sql 复制代码
SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

查右表没匹配的行,这个不会被消除。还有条件放在左表上也不会:

sql 复制代码
SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t1.status = 1;

后来我就改了个写法,把右表的条件挪到ON里:

sql 复制代码
SELECT * 
FROM t1 LEFT JOIN t2 
ON t1.id1 = t2.id2 AND t2.name2 = 'cc';

这样一来执行顺序变了:先对t2做过滤,再跟t1做LEFT JOIN,t1所有行都保留。

当时在原MySQL上跑同样的SQL,没这个问题。到了金仓上优化器太聪明了,替用户做了决定,反而把业务搞错了。

这事之后我就养成了一个习惯,所有涉及LEFT JOIN的SQL都单独过一遍。

先跑一下执行计划,看看原本的LEFT JOIN还在不在。再找几条右表无匹配的数据验证一下:

sql 复制代码
SELECT * FROM t1 WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE t1.id = t2.id) LIMIT 10;

如果这些数据在完整查询里消失了,说明外连接被消掉了,得改。

那次十几条数据,让我们加了一整天的班。后来每次写LEFT JOIN,我都会想起那天晚上。

相关推荐
花间相见1 小时前
【计算基础|Redis02】【上手】五大数据类型命令逐条实操
数据库·redis·后端
GISer_Jing1 小时前
AI Agent秋招面试万字通关指南|架构、ReAct、上下文工程、RAG、评测、生产运维全解
后端·ai·langchain
Moment2 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
学长毕设3 小时前
基于SpringBoot的游乐园管理系统-附源码
java·spring boot·后端
橙序员小站3 小时前
Windows 安装包反复报错?一次排查补上了 5 个 CI 检查点
后端
陈随易3 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
SimonKing3 小时前
震惊:怎么回事,opencode一轮对话耗尽免费额度
java·后端·程序员
张彦峰ZYF4 小时前
功能齐了不等于能上线:智能工单系统的AI回归测试、安全防护、成本可观测与CI/CD生产部署
后端·企业智能工单系统·评测线·安全线·成本线·部署线
Rain的Java大神之路4 小时前
LeetCode 37 解数独面试攻略:回溯 + 位掩码 + MRV,从暴力到毫秒级求解
java·后端·leetcode
量化分析码农4 小时前
【Python量化波动率实战 05】你的组合真的分散了吗:滚动相关与分散化收益
后端