char 和 varchar 的区别?
char 和 varchar 的区别?
zhangchangsheng面试考察点
- 基础掌握度:面试官不仅仅是想知道两个类型的字面区别,更是想知道你是否理解 MySQL 的存储机制,能否在实际表设计中做出正确选择。
- 性能意识:考察你是否清楚定长和变长类型在存储效率、查询性能、索引构建等方面的差异,以及在不同场景下的取舍。
- 实践经验:能否结合实际业务场景(如用户名、手机号、MD5 值等)给出合理的选择建议,而不是只会背概念。
核心答案
CHAR 和 VARCHAR 是 MySQL 中两种最常用的字符串类型,核心区别如下:
| 对比维度 | CHAR | VARCHAR |
|---|---|---|
| 存储方式 | 定长存储,不足补空格 | 变长存储,按实际长度 |
| 长度范围 | 0 ~ 255 字符 | 0 ~ 65,535 字节 |
| 空间占用 | 固定占用声明长度 | 实际长度 + 1~2 字节前缀 |
| 尾部空格 | 存储时补齐,检索时移除 | 原样存储和检索 |
| 性能特点 | 更快的 CRUD(无长度计算) | 更省空间(按需分配) |
| 适用场景 | 长度固定的数据(手机号、MD5) | 长度变化的数据(用户名、地址) |
一句话总结:CHAR 是定长、空间换时间;VARCHAR 是变长、时间换空间。
深度解析
一、存储机制对比
| 存储示例 | 存储方式 | 占用空间 | 说明 |
|---|---|---|---|
| CHAR(10) 存 ‘abc’ | 固定长度,不足补 7 个空格 | 10 字节 | 固定占用声明长度 |
| VARCHAR(10) 存 ‘abc’ | 1 字节长度前缀 + 3 字节实际数据 | 1 + 3 = 4 字节 | 按实际长度存储 |
| VARCHAR(10) 存 ‘abcdefghij’ | 1 字节长度前缀 + 10 字符 | 1 + 10 = 11 字节 | 长度前缀 + 实际数据 |
结论:CHAR 固定长度、不足补空格,适合定长数据(如手机号、身份证号);VARCHAR 可变长度、按需存储,适合变长数据(如用户名、地址)。
上图展示了 CHAR 和 VARCHAR 的存储差异,核心要点如下:
- CHAR 定长机制:无论实际存储多少字符,都占用声明长度的空间。比如
CHAR(10)存储'abc'时,会自动补 7 个空格,占用 10 字节。检索时,尾部的空格会被自动移除(这是一个容易踩坑的点)。 - VARCHAR 变长机制:只占用实际需要的空间,额外使用 1~2 字节存储长度信息。当长度 ≤ 255 字节时用 1 字节,超过 255 字节时用 2 字节。
- 空间计算示例:
CHAR(10)存储'abc'→ 占用 10 字节VARCHAR(10)存储'abc'→ 占用 4 字节(1 长度 + 3 数据)VARCHAR(1000)存储'abc'→ 占用 5 字节(2 长度 + 3 数据)
二、尾部空格处理差异(高频考点)
-- CHAR 尾部空格会被移除 |
关键差异:
CHAR:存储时补空格,检索时自动移除尾部空格VARCHAR:原样存储,原样检索
三、InnoDB 行溢出与页存储
在 InnoDB 存储引擎中,VARCHAR 的最大长度受多个因素限制:
flowchart TB
R["VARCHAR 长度限制因素"] --> A["单列最大长度"]
A --> A1["最多 65,535 字节(所有列共享)"]
R --> B["行格式影响"]
B --> B1["COMPACT/REDUNDANT:超过 768 字节可能溢出"]
B --> B2["DYNAMIC/COMPRESSED:超过 40 字节可能溢出"]
R --> C["字符集影响"]
C --> C1["utf8mb4:1 字符最多占 4 字节"]
C --> C2["utf8:1 字符最多占 3 字节"]
C --> C3["latin1:1 字符占 1 字节"]
R --> D["示例:VARCHAR(255) 实际占用"]
D --> D1["latin1:255 + 1 = 256 字节"]
D --> D2["utf8:255 x 3 + 2 = 767 字节"]
D --> D3["utf8mb4:255 x 4 + 2 = 1022 字节"]
关键点:
VARCHAR(N)中的 N 是字符数,不是字节数- 在
utf8mb4字符集下,VARCHAR(255)最多占用255 × 4 + 2 = 1022字节 - 当数据过大时,InnoDB 会使用”行溢出”机制,将数据存储到溢出页
四、性能对比
| 操作类型 | CHAR 表现 | VARCHAR 表现 |
|---|---|---|
| INSERT | 稍快(无需计算长度) | 稍慢(需计算实际长度) |
| UPDATE | 更快(长度不变,无碎片) | 可能产生碎片(长度变化) |
| SELECT | 更快(固定位置计算) | 稍慢(需解析长度前缀) |
| 索引构建 | 更快(长度固定) | 稍慢(需遍历计算) |
| 存储空间 | 浪费(固定长度) | 节省(按需分配) |
性能结论:
CHAR在频繁更新场景下更有优势(不会产生碎片)VARCHAR在存储空间上更有优势(尤其数据长度差异大时)- 实际应用中,这个性能差异通常可以忽略,空间利用率往往是更重要的考量
五、最佳实践
-- ✅ 推荐使用 CHAR 的场景(长度固定) |
六、常见误区
-- ❌ 误区一:认为 CHAR(10) 只能存 10 个英文字符 |
面试高频追问
- VARCHAR(10) 和 VARCHAR(1000) 存储 ‘abc’ 有区别吗?
- 存储空间:磁盘上没区别(都占用 4 字节)
- 内存占用:排序、临时表等场景下,VARCHAR(1000) 会按声明长度预分配内存,更占内存
- 建议:在满足业务需求的前提下,尽量使用较小的长度声明
- 为什么 CHAR 最多只能 255 字符?
CHAR的长度用 1 字节存储,最大值就是 255VARCHAR用 1~2 字节存储长度,所以能支持更大的值
- 索引中使用 CHAR 还是 VARCHAR 更好?
- 对于固定长度的字段(如手机号),
CHAR更好(索引更紧凑) - 对于变长字段,必须用
VARCHAR - 无论哪种,都建议加上前缀索引以减少索引大小
- 对于固定长度的字段(如手机号),
- TEXT 类型什么时候用?
- 超过 255 字符的定长数据:不存在,改用
VARCHAR或TEXT - 超过 65,535 字节的大文本:使用
TEXT系列(TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT)
- 超过 255 字符的定长数据:不存在,改用
常见面试变体
- “数据库中定长字段和变长字段有什么区别?”
- “设计用户表时,手机号和用户名分别用什么类型?为什么?”
- “VARCHAR(255) 在 utf8mb4 字符集下最多能存多少个汉字?”
- “CHAR 和 VARCHAR 在索引构建上有什么差异?”
记忆口诀
CHAR 定长补空格,检索之时去空格; VARCHAR 变长按需存,长度前缀记心间。 手机身份证用 CHAR,用户邮箱用 VARCHAR。
总结
CHAR 是定长类型,存储时补空格、检索时去空格,适合长度固定的数据(手机号、MD5 值);VARCHAR 是变长类型,按实际长度存储,额外使用 1~2 字节记录长度,适合长度变化的数据(用户名、地址)。选择原则:固定长度用 CHAR,变化长度用 VARCHAR,性能差异通常可以忽略,优先考虑空间利用率和业务语义。
声明:本文转载自小哈的博客 《char 和 varchar 的区别?》,版权归原文作者所有。转载请保留本声明与原文链接。
评论
匿名评论隐私政策
WalineTwikoo
