空字符串 ” 与 NULL 在 SQL 中语义不同:” 是有效零长字符串,NULL 表示未知 / 缺失;误用会导致业务逻辑错误、索引失效或全表误更新。

UPDATE 字段设为空字符串时,别误写成 SET column = NULL
空字符串 '' 和 NULL 在 SQL 里是完全不同的东西:前者是长度为 0 的有效字符串值,后者代表“未知 / 缺失”。很多业务逻辑(比如前端判空、索引行为、聚合函数结果)都依赖这个区别。
常见错误现象:UPDATE users SET name = NULL WHERE id = 123 执行后,name 变成 NULL,但业务本意其实是清空昵称,保留“已设置为空”的语义。
- 明确用
''(两个单引号)表示空字符串,不是""、不是空格、不是NULL - 如果字段定义为
NOT NULL,设NULL会直接报错:ERROR 1048 (23000): Column 'name' cannot be null - MySQL 默认允许空字符串存入
NOT NULL字段;PostgreSQL 同样支持,但需确认字段没加CHECK (column '')类约束
WHERE 条件漏写或写错,导致全表被误更新为空字符串
这是线上事故高发点。空字符串本身无害,但批量覆写就致命——尤其当开发在测试环境验证时只查了 1 行,上线后却影响上万条。
使用场景:后台运营导出用户列表后,人工筛选一批 ID,想批量清空他们的备注字段。
- 务必先用
SELECT预查:SELECT id, remark FROM users WHERE id IN (101,102,103); - 再执行
UPDATE users SET remark = '' WHERE id IN (101,102,103); - 禁止省略
WHERE;哪怕临时加AND 1=0测试语法也比不加强 - 某些 ORM(如 Django ORM 的
.update())默认不带WHERE保护,得靠人盯住生成的 SQL
MySQL 中空字符串与 NULL 在索引和查询中的表现差异
如果你对字段建了索引又常查 remark = '',得知道它和 remark IS NULL 是两条路,索引能用,但统计信息、执行计划可能不同。
性能影响:空字符串可被普通 B+ 树索引正常定位;NULL 值在 MySQL 索引中单独存放,部分版本下 IS NULL 走索引效率略低。
-
WHERE remark = ''能走索引,前提是该列没被函数包裹(如TRIM(remark) =''就不能) -
WHERE remark IS NULL也能走索引,但优化器可能因 NULL 值比例高而放弃索引,改用全表扫描 - 混合查询要注意:
remark IN ('', NULL)不生效——SQL 标准里NULL =''永远为UNKNOWN,必须拆成remark = '' OR remark IS NULL
程序传参时,空字符串被自动转成 NULL(尤其 ORM 或 JDBC 场景)
Java 用 MyBatis,Python 用 SQLAlchemy,甚至 Node.js 的 pg 库,都可能把空字符串当作“空值”并悄悄映射成 NULL 写入数据库,你写的 SQL 没问题,但框架截胡了。
常见错误现象:代码里明明写了 user.remark = '',日志里看到的 SQL 却是 SET remark = NULL。
- MyBatis:检查
jdbcType是否设为VARCHAR,避免用NULL类型推断;禁用useActualParamName=false导致参数丢失 - SQLAlchemy:确认字段定义没加
nullable=False还配了default=None,这会让空字符串被覆盖为 None → NULL - JDBC URL 加
stringtype=unspecified(PostgreSQL)或确认驱动版本,老版 mysql-connector-java 对空字符串处理不一致
最稳的办法:在应用层打日志输出最终拼出的 SQL,而不是只信 ORM 的 debug 日志。空字符串这事,信自己看的那行 SET remark = '',不信任何“应该”。