线上问题: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开发规范》

相关推荐
GreenTea7 小时前
GrokBot 核心成员 Lauren Tan:每月交付 2000 个 PR 的人,是怎么用 AI 的
前端·后端·架构
码事漫谈7 小时前
FDE:一个缩写,两种命运
后端
名字还没想好☜8 小时前
Go context.AfterFunc 实战(Go 1.21):context 一取消就自动跑清理,告别手写 goroutine 监听 Done
后端·golang·go
明月_清风9 小时前
为什么最近开始关注 JEV?几个实战案例告诉你答案
人工智能·后端
GetcharZp10 小时前
5 分钟拥有自己的 S3:RustFS 上手(MinIO 的 Rust 替代,Apache 2.0 可商用)
后端
‎ദ്ദിᵔ.˛.ᵔ₎10 小时前
MySQL 表约束
数据库·mysql
行百里er11 小时前
Redis 版本演进、新特性与协议那些事儿
redis·后端
Joy T11 小时前
Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景
java·人工智能·后端·spring·agent入门·agent state
打工仔折腾 AI12 小时前
FastAPI 从本机到生产服务器:Nginx+Gunicorn+Uvicorn 完整部署实录
人工智能·后端·python·nginx·fastapi·gunicorn