MySQL WHERE子句中用NULL替代整数/字符串是否影响查询性能?
实际表现结论
两种传参方式不仅查询结果可能天差地别,性能表现也完全不一样,本质上是MySQL对NULL的比较规则、优化器逻辑、索引存储规则决定的,不同场景下差异很大,没有统一的“更快/更慢”结论。
- 先讲最容易踩的语义坑:你示例里的写法是
param_three = QUESTIONABLE_VALUE,如果这里传入的是NULL,在MySQL默认规则下,任何值和NULL用=/<>这类普通比较运算符运算的结果都是UNKNOWN,放到WHERE子句里会直接判定为条件不成立,最终查询不会返回任何行——这和传入普通整数、字符串的逻辑完全不同,后者是匹配列值和传入参数相等的行。 - 对应到性能上,如果你确实就是写的
param_three = NULL(不管是直接写死SQL,还是用预编译语句绑定NULL参数,没有用NULL安全的比较运算符),MySQL优化器在解析阶段就能识别出这个条件恒为假,执行计划会直接走Impossible WHERE逻辑,连表、索引都不会扫,直接返回空结果,这个执行速度比你传普通值走索引查还要快。你随便拿个测试表跑EXPLAIN就能验证,这种场景下Extra列会明确显示Impossible WHERE noticed after reading const tables。 - 如果你本来就是要查字段为NULL的行,用了正确的写法
param_three IS NULL或者NULL安全等值运算符param_three <=> QUESTIONABLE_VALUE(这时候QUESTIONABLE_VALUE传NULL才是匹配NULL行的语义),性能和传普通值的差异要看实际表结构和数据分布:- 如果
param_three字段建表时加了NOT NULL约束,优化器同样能在解析阶段识别出IS NULL条件恒假,直接返回空结果,没有额外开销。 - 如果
param_three允许为NULL,且字段上建了二级索引,InnoDB是会把NULL值存在二级索引树里的:如果表中NULL值的占比很低,优化器会选择走二级索引查询,性能和普通等值查询没有可感知的差异;如果NULL值占比很高,优化器判定走索引的回表开销比全表扫还大,就会选全表扫描,这时候性能会比传区分度高的普通整数、字符串差不少。
- 如果
- 额外提个实际开发中经常碰到的坑:不少ORM框架在构造查询语句的时候,如果检测到你传入的参数是NULL,会自动把你写的
col = ?语法转换成col IS NULL,这时候就不会触发前面说的恒假条件优化,会真的去查字段值为NULL的行,性能表现就完全看索引和数据分布了,别想当然以为生成的SQL还是你手写的= NULL逻辑。 - 别信网上很早之前传的“查NULL一定会全表扫”的过时结论,MySQL 5.6及之后的版本,InnoDB对索引上NULL值的等值查询优化已经很成熟,只要NULL值的区分度足够,走索引的效率和普通值查询没有区别。
内容的提问来源于stack exchange,提问作者Tomasz Wu
相关产品推荐
相关产品推荐

