今天,马六学上弄了一个活动,鼓励大家分享自己最硬核的数据库经验(可以是坑、技巧或冷知识)。
活动地址:
https://www.maliustudy.com/post_detail/262
其中,有一位朋友留言。

看这条SQL,第一感觉是,如果course没有id这个字段,执行之后,应该要提示字段不存在才合理。
但实际返回了数据。
我也是很好奇,然后做了一个实验。
创建测试表:
CREATE TABLE `t1_0807` (`id` int NOT NULL AUTO_INCREMENT,`a` int DEFAULT NULL,b varchar(10),PRIMARY KEY (`id`),KEY `idx_a` (`a`)) ENGINE=InnoDB;CREATE TABLE `t2_0807` (`id` int NOT NULL AUTO_INCREMENT,`c` int DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB;
写入测试数据:
insert into t1_0807(a,b) values (1,'one'),(2,'two'),(3,NULL);insert into t2_0807(c) values (1),(2),(3);
查询:
select * from t1_0807 where b in (select b from t2_0807);

果然,复现了,t2_0807没有b字段,也返回了数据,MySQL版本是8.0.25。
估计是优化器改写的时候出的问题。
我们先查看执行计划:
explain select * from t1_0807 where b in (select b from t2_0807);
查看warnings,就能看到优化器是怎么改写SQL的。
show warnings;

原来是SQL被优化器改写成了:
select#1 */ select `martin`.`t1_0807`.`id` AS `id`,`martin`.`t1_0807`.`a` AS `a`,`martin`.`t1_0807`.`b` AS `b` from `martin`.`t1_0807` semi join (`martin`.`t2_0807`) where (`martin`.`t1_0807`.`b` = `martin`.`t1_0807`.`b`
大家在使用子查询的时候得小心了哈,一个好的习惯就是在更新或者删除前,先查询一下,看是不是符合预期。
像这位同学的留言,应该就是研发没先执行查询,直接更新导致全表数据被错误更新了。
近期文章
文章转载自MySQL数据库联盟,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




