[
新星杯·14天创作挑战营·第17期
10w+人浏览
421人参与
](https://activity.csdn.net/writing?id=11028)
这是一个在 MySQL 面试和日常开发中非常经典的问题。CHAR 和 VARCHAR 是两种最常用的字符串数据类型,它们的核心区别在于存储和检索的方式。
下面我将从多个维度详细解释它们的区别,并给出选择建议。
| 特性 | CHAR | VARCHAR |
|---|---|---|
| 长度处理 | 固定长度 | 可变长度 |
| 存储方式 | 分配定义的全部空间,不足部分用空格填充 | 只存储实际字符数(+1或+2字节存储长度信息) |
| 存储空间 | 固定,为声明的长度 | 可变,为实际字符串长度 + 长度前缀 |
| 尾部空格 | 检索时会自动删除 | 检索时会保留 |
| 读取速度 | 较快(固定长度,无需计算) | 稍慢(需要根据长度信息读取) |
| 适用场景 | 长度固定或近乎固定的数据(如MD5、UUID、状态码) | 长度变化较大的数据(如姓名、地址、描述) |
CHAR(n):
CHAR(10) 的列,无论你存入 "hi"(2字符)还是 "hello"(5字符),MySQL 都会在磁盘上分配并占用 10 个字符的空间。"A" 到 CHAR(4) 列,实际存储的是 "A "。VARCHAR(n):
你声明一个 VARCHAR(10) 的列,存入 "hi" 大约占用 3 个字节(2个字符 + 1字节的长度前缀),存入 "hello" 大约占用 6 个字节(5个字符 + 1字节的长度前缀)。
VARCHAR 需要使用额外的 1 或 2 个字节来存储“字符串的长度”这个信息。
n <= 255,则使用 1 个字节 作为长度前缀。n > 255,则使用 2 个字节 作为长度前缀。它只存储实际的字符串内容,不会用空格填充。
这是另一个非常重要的区别,尤其是在进行字符串比较时。
CHAR:在检索(SELECT)时会自动移除存储时填充的尾部空格。
-- 假设有一个 CHAR(5) 的列
INSERT INTO table (char_column) VALUES ('abc '); -- 存储为 'abc '
SELECT char_column, LENGTH(char_column) FROM table;
-- 检索结果:'abc',长度为 3(尾部空格被移除)
* **`VARCHAR`**:在**检索时会保留**尾部空格。
```
-- 假设有一个 VARCHAR(5) 的列
INSERT INTO table (varchar_column) VALUES ('abc '); -- 存储 'abc ' 及其长度信息
SELECT varchar_column, LENGTH(varchar_column) FROM table;
-- 检索结果:'abc ',长度为 5(尾部空格被保留)
```
注意:由于
CHAR的这种行为,当使用=比较时:
'abc '(CHAR)和'abc'(CHAR)是相等的;
'abc '(CHAR)和'abc'(VARCHAR)是相等的;
'abc '(VARCHAR)和'abc'(VARCHAR)是不相等的。
CHAR:
VARCHAR:
请根据你的业务场景来决定:
使用 CHAR 的情况:
存储的字符串长度非常固定或变化极小。
经典例子:
CHAR(36),但现在更推荐存储为二进制或使用 UUID_SHORT())CHAR(2) 用于 'US', 'CN')CHAR(1) 用于 'Y'/‘N’)避免使用CHAR的情况:
使用 VARCHAR 的情况:
CREATE TABLE test_string (
id INT PRIMARY KEY,
fixed_char CHAR(5),
variable_varchar VARCHAR(5)
);
INSERT INTO test_string (id, fixed_char, variable_varchar) VALUES
(1, 'A', 'A'), -- CHAR存储 'A ', VARCHAR存储 'A'
(2, 'ABCDE', 'ABCDE'); -- 两者都存满
-- 查询并显示长度
SELECT
fixed_char,
LENGTH(fixed_char) as char_length,
variable_varchar,
LENGTH(variable_varchar) as varchar_length
FROM test_string;
结果可能如下:
| fixed_char | char_length | variable_varchar | varchar_length |
|---|---|---|---|
| A | 1 | A | 1 |
| ABCDE | 5 | ABCDE | 5 |
VARCHAR。这是绝大多数场景下的选择。CHAR。CHAR 会剔除检索结果的尾部空格 这一点,可以避免很多意想不到的查询 Bug。在现代 MySQL 版本和 InnoDB 存储引擎下,对于大多数通用场景,VARCHAR 因其灵活性而更受欢迎。除非你非常确定某个字段的长度是绝对固定的,否则从 VARCHAR 开始通常是一个安全的选择。