在数据库中,VARCHAR 和 CHAR 都是用于存储字符串的数据类型,但它们在存储方式、空间占用和适用场景上有本质区别。以下是核心对比:
1. 存储方式与空间占用
| 特性 | CHAR | VARCHAR |
|---|
| 存储方式 | 定长存储 | 变长存储 |
| 空间分配 | 固定长度(声明长度) | 实际数据长度 + 长度前缀(1-2字节) |
| 未用空间 | 用空格填充剩余长度,占用固定空间 | 仅存储实际数据,无空间浪费 |
| 示例 | CHAR(10) 存储 "abc" → 占用 10字节 | VARCHAR(10) 存储 "abc" → 占用 3字节+长度前缀 |
2. 性能对比
| 场景 | CHAR | VARCHAR |
|---|
| 读取速度 | ✅ 更快(固定长度,直接定位) | ⚠️ 稍慢(需解析长度前缀) |
| 更新速度 | ⚠️ 若新数据长度不变则快,否则需重写整行 | ✅ 更灵活(允许长度变化) |
| 存储碎片 | ✅ 不易产生碎片 | ⚠️ 频繁更新变长数据可能产生碎片 |
3. 长度限制
| 类型 | 最大长度 | 说明 |
|---|
| CHAR | 255字符(MySQL) | 超过时自动转换为 TEXT 类型 |
| VARCHAR | 65,535字节(MySQL,受行大小限制) | UTF8 编码下约 21,844 个汉字 |
4. 适用场景
✅ 优先用 CHAR 的情况
- 存储长度固定的数据(如 MD5 哈希值、邮编、国家代码)
country_code CHAR(2)
- 频繁更新且长度不变的数据(减少碎片)
- 需要精确长度比较的场景(无尾部空格问题)
✅ 优先用 VARCHAR 的情况
- 存储长度变化大的数据(如用户名、地址、描述文本)
username VARCHAR(50)
- 节省存储空间(尤其是大表或长文本)
- 数据尾部空格需保留的场景(CHAR 会自动截断尾部空格)
关键区别总结
| 对比维度 | CHAR | VARCHAR |
|---|
| 存储机制 | 定长(空格填充) | 变长(仅存有效字符) |
| 空间效率 | 低(可能浪费空间) | 高(按需分配空间) |
| 读取性能 | 高(无需计算长度) | 中(需解析长度前缀) |
| 尾部空格 | 自动移除(检索时丢失) | 保留原样 |
| 索引效率 | 高(适合固定长度索引) | 中(索引计算稍复杂) |
经典示例分析
存储字符串 "SQL"(实际长度=3字节)
CREATE TABLE test (
fixed CHAR(10),
dynamic VARCHAR(10)
);
- 存储空间:
CHAR(10) 是 VARCHAR(10) 的 2.5倍 - 存储内容:
CHAR → "SQL "(补7空格)VARCHAR → "SQL"(原样存储)
选择建议
- 固定长度数据 →
CHAR
(如 UUID、手机号、枚举代码) - 长度变化 ≤ 20% →
CHAR
(减少碎片,提升读取速度) - 长度变化大或长文本 →
VARCHAR
(如 文章内容、用户评论) - 存储敏感型尾部空格 →
VARCHAR
(CHAR 会丢失原始空格)
💡 终极原则:
- 追求 性能 且 长度固定 →
CHAR - 追求 空间效率 且 长度不定 →
VARCHAR