MySQL允许字段存NULL,这事儿往往就是个大坑。《数据库架构100讲》第15课讲到了这个。大家平时用ALL这种全表扫描时,遇到这种场景吗? 我给大家做个实验。我用CREATE TABLE建了张user表,id是个非唯一索引,允许NULL。先往里插几条数据,shenjian、zhangsan和lisi。 第一个问题:SELECT * FROM user WHERE id != 1,结果会是什么? 答案肯定是shenjian、zhangsan和lisi这三个人,对吧?因为表里没1的话就全出来了。 但别急着下结论。再往里插一行数据,这次只填名字,name是wangwu。这时候问题来了,表里的id变成NULL了。 第二个问题:再跑一次SELECT * FROM user WHERE id != 1,这回结果还是3条吗? 错了!结果集只有2条!那个id为NULL的wangwu居然没出来。 为什么会这样? 首先要明白负向查询的坑:不等于( != )查询会导致全表扫描。用EXPLAIN看一眼就清楚了,type是ALL,rows是3。 然后是第二个大坑:允许空值的话,不等于查询根本不会把NULL行算进去。 如果你想让wangwu也出来,就得加个OR条件。SELECT * FROM user WHERE id != 1 OR id IS NULL; 结果就全对了。 第三个知识点更恶心:有些OR条件可能又会导致全表扫描。这时候该怎么办?得把它优化成UNION查询。 我用EXPLAIN分别测了测: 单独查id=1或者id IS NULL都能走索引; 但如果把它们写在同一个SQL语句里用OR连起来,又变成全表扫描了; 这时候就把它拆成两个UNION查询就行了。 总结一下: 第一,负向比较(比如!=)容易引发全表扫描; 第二,如果允许NULL值,用!=查的时候不会把NULL行算进去; 第三,OR可能导致全表扫描; 第四,建表时给字段加个默认值能防坑; 第五,多用EXPLAIN工具看执行计划。