线上问题:MySQL NULL值引发的投诉

一、前言

2025.08.07 线上收到测试同学反馈,几个商机客户在商机公海里搜索不到,需要协助查看。

一开始以为是对应销售同学没有配置好对应池,所以才搜索不到。

销管明确说已正确配置池,并提供搜索不到商机客户的 clientId。测试同学和产品同同学也一起尝试了,发现确实搜索不到。

反馈到我这,让帮忙排查下。

通过接口开始排查:

  1. 加密搜索是否有问题:邮箱搜索是先加密再搜索
  2. 查询 SQL 是否有问题:字段问题

发现有 userStatus 字段,使用 NOT IN 查询。

在线上使用相同 SQL,加上 userStatus not in ('Unbind','Blocked')确实搜索不到。

且对应 clientId 中 userStatus 的值是 NULL。

那就是这块有问题,正常客户的 userStatus 不能为 NULL。

且在 MySQL / ADB 中,当 userStatus 字段为 null 时,使用 NOT IN 搜索不到。

这是因为在 SQL 中,任何与 NULL 的比较操作(包括 INNOT IN)都会返回 NULL(未知),而不是 TRUEFALSE。在 WHERE 子句中,只有返回 TRUE 的记录才会被包含在结果集中。

修正方法:

  1. 线上数据订正:将对应的数据的 userStatus 改为正常值
  2. 修改查询 SQL:支持 userStatus 为 NULL,SQL 如下
sql 复制代码
SELECT * FROM customer 
    WHERE clientId = '123'AND (ownerId IS NULL OR ownerId = '')  AND (userStatus IS NULL OR userStatus NOT IN ('Unbind','Blocked'))

Hotfix:找到原因,跟当时开发同学沟通并确定,让其先补数据,并让其事后TODO修复。

PS:这块是工作了8年的前阿里同学写的。基础不扎实,小问题也会放大。

二、小结

为什么很多人建议 MySQL 字段不要设置为 NULL

主要原因并不是说 NULL 一定不好,而是它在实际使用中会带来一些性能、语义和维护上的问题。

  1. NULL 的语义复杂:在 SQL 中,NULL 表示"未知"或"不存在",它不是 0、空字符串、false,也不是任何具体值。

    sql 复制代码
    -- 这意味着在比较时,NULL 有特殊规则:
    SELECT * FROM customer WHERE userStatus = NULL; -- 永远返回空结果
    SELECT * FROM customer WHERE userStatus IS NULL; -- 才能判断是否为 NULL
    
    -- 如果开发人员不熟悉这些规则,很容易写出错误的查询。
  2. 索引和性能问题:在 MySQL(尤其是 InnoDB)中,NULL 值会影响索引存储方式。

    1. 对含有 NULL 的列建立索引时,MySQL 会额外存储一个标志位来表示该值是否为 NULL,这会增加索引空间占用。
    2. 某些情况下,NULL 会让索引选择性降低,影响查询优化器的执行计划。
  3. 聚合和统计的复杂性:COUNT(column) 不会统计 NULL 值,而 COUNT(*) 会统计所有行。

    sql 复制代码
    SELECT COUNT(status) FROM customer; -- 不统计 status 为 NULL 的行
    SELECT COUNT(*) FROM customer;      -- 统计所有行
  4. 存储上的差异:NULL 列会额外占用 1 bit 的空间来记录是否为 NULL

Tips:好的编程习惯可以避免很多低级错误。

Java 开发者都需要学习:《阿里巴巴Java开发规范》

相关推荐
存在的五月雨10 小时前
Spring Security认证流程
java·开发语言·mysql
禹凕10 小时前
Python编程——进阶知识(MYSQL引导入门)
开发语言·python·mysql
Victor35610 小时前
MongoDB(2)MongoDB与传统关系型数据库的主要区别是什么?
后端
JaguarJack10 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
BingoGo10 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端
Victor35610 小时前
MongoDB(3)什么是文档(Document)?
后端
牛奔12 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌17 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX18 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了18 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结