MySQL 表设计终极指南:为什么避免 NULL 是提升性能的关键?
在数据库设计中,字段是否允许为 NULL
常常被开发者忽略,但它却深刻影响着查询性能、存储效率和数据可靠性。本文将通过原理剖析、场景对比和实战建议,揭示 NULL
值在 MySQL 中的隐藏成本,并提供一套完整的最佳实践方案。
一、索引与 NULL 的真相:打破三大误区
误区1️⃣:NULL 字段无法使用索引
事实:
-
普通索引:完全存储
NULL
值,WHERE col IS NULL
可触发索引扫描 -
唯一索引:允许存在多个
NULL
,索引条目包含NULL
值
验证实验:
-- 建表并插入50万数据(30%为NULL)
CREATE TABLE user_actions (
id INT PRIMARY KEY,
action_type INT,
INDEX idx_action (action_type)
);
INSERT INTO user_actions
SELECT
n,
IF(RAND() < 0.3, NULL, FLOOR(RAND()*10))
FROM numbers(1, 500000);
-- 查询NULL值
EXPLAIN SELECT * FROM user_actions
WHERE action_type IS NULL;
-- 显示使用 idx_action 索引
误区2️⃣:NULL 比空值更省空间
真相:
-
可变长度类型:
NULL
比空字符串节省 1-2 字节长度信息 -
固定长度类型:
NULL
与默认值(如 0)存储开销相同
存储对比表:
数据类型 | NULL存储 | 空字符串存储 | 默认值存储(如0) |
---|---|---|---|
VARCHAR(255) | 0字节 | 1字节 | 1字节 |
INT | 0字节 | - | 4字节 |
TEXT | 0字节 | 2字节 | 2字节 |
误区3️⃣:所有场景都应禁用 NULL
例外情况:
- 医疗记录中未检测的指标
- 用户问卷中的可选问题
- 稀疏监控数据(99%时间无异常)
二、NULL 的四大隐性成本
成本1️⃣:查询复杂度指数级增长
问题案例:
统计过去一年活跃用户(最后登录时间非空)
-- 允许NULL的写法
SELECT COUNT(*) FROM users
WHERE last_login IS NOT NULL
AND last_login > '2023-01-01';
-- 非NULL设计(默认值'1970-01-01')
SELECT COUNT(*) FROM users
WHERE last_login > '2023-01-01';
性能差异:
- 执行时间缩短 40%(移除 IS NOT NULL 判断)
- 索引扫描行数减少 30%
成本2️⃣:索引失效的隐形推手
失效场景:
-- 联合索引 (status, deleted_at)
SELECT * FROM orders
WHERE status = 'paid'
AND COALESCE
上一篇: 几秒钟就充满电!科学
下一篇: 暂无数据