字符串数据类型
本教程共 46 篇 · 第 8 篇 · 更新于 2026-07-30 · 约 13 分钟阅读
8. 字符串数据类型
本节目标:搞懂 CHAR 和 VARCHAR 的根本区别,知道什么时候用定长、什么时候用变长,理解 TEXT 系列的四个档位,学会按内容长度挑对字符串类型,避免空间浪费和截断。
字符串类型在建表里用得最多—用户名、邮箱、文章内容、状态码都是字符串。这一节把字符类型讲透,重点是 CHAR 和 VARCHAR 的取舍。
8.1 字符串类型一览
MySQL 的字符串类型主要分这几类:
| 类型 | 用途 | 最大长度 |
|---|---|---|
CHAR(M) | 定长字符串 | 255 字符 |
VARCHAR(M) | 变长字符串 | 65,535 字节(受行大小限制) |
TINYTEXT | 短文本 | 255 字节 |
TEXT | 普通文本 | 65,535 字节 |
MEDIUMTEXT | 中等文本 | 16 MB |
LONGTEXT | 大文本 | 4 GB |
ENUM | 枚举(下节讲) | - |
SET | 集合(下节讲) | - |
Note
CHAR(M)和VARCHAR(M)里的M是字符数,不是字节数。比如CHAR(30)能存 30 个字符,无论是英文还是中文。具体占多少字节,取决于字符集(utf8mb4 下一个中文占 3~4 字节)。
8.2 CHAR:定长字符串
CHAR(M) 是定长类型。你定义 CHAR(10),不管存几个字符,永远占 10 个字符的空间。存不够就用空格在右边补齐。
CREATE TABLE t (
code CHAR(5)
);
INSERT INTO t VALUES('ab'), ('abcde');
- 存
'ab',实际存的是'ab '(后面补 3 个空格); - 存
'abcde',正好 5 个字符,原样存。
读取时,MySQL 会自动去掉尾部的空格,所以你存 'ab' 取出来还是 'ab'。
CHAR 的适用场景
定长的特点决定了它适合长度固定或基本固定的数据:
- 国家代码
'CN'、'US',用CHAR(2); - 性别
'M'/'F',用CHAR(1); - 手机号 11 位,用
CHAR(11); - 固定长度编码、状态码。
定长的优势是查询快:每行长度一样,MySQL 算偏移量很轻松,不用扫长度前缀。
Warning
CHAR默认会去尾空格。如果开了PAD_CHAR_TO_FULL_LENGTHSQL 模式,取出来才保留尾部空格。一般不用开。
8.3 VARCHAR:变长字符串
VARCHAR(M) 是变长类型。定义 VARCHAR(255),实际只占已存字符的长度 + 1~2 字节长度前缀。存多少占多少,不补空格。
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
INSERT INTO users VALUES(1, 'zhangsan', 'zs@example.com');
存 'zhangsan'(9 个字符),按 utf8mb4 算大约占 9~36 字节加 1 字节长度前缀,而不是占满 50 个字符的空间。
长度前缀
VARCHAR 用 1 或 2 字节记录实际长度:
- 实际占用 ≤ 255 字节:1 字节前缀;
- 实际占用 > 255 字节:2 字节前缀。
这部分是 MySQL 自动管的,你不用操心,知道有这个开销就行。
VARCHAR 的尾部空格
和 CHAR 不同,VARCHAR 保留尾部空格:
CREATE TABLE t2 (v VARCHAR(5));
INSERT INTO t2 VALUES('ab '); -- 存 'ab' 加 3 个空格
mysql> SELECT v, LENGTH(v) FROM t2;
+------+-----------+
| v | LENGTH(v) |
+------+-----------+
| ab | 5 |
+------+-----------+
长度是 5,空格被保留下来了。但如果存的值加上尾部空格超过了定义长度,MySQL 会截断并给警告:
INSERT INTO t2 VALUES('abcde '); -- 7 个字符,超过 5
-- 实际存 'abcde',尾部空格被截断,1 个 warning
8.4 CHAR vs VARCHAR 怎么选
这是面试和实战的高频问题。核心区别:
| 对比项 | CHAR | VARCHAR |
|---|---|---|
| 长度 | 固定 | 可变 |
| 存储 | 占满定义长度 | 实际长度 + 前缀 |
| 尾部空格 | 存时补齐,取时去掉 | 保留 |
| 查询速度 | 略快 | 略慢(要算长度) |
| 空间浪费 | 长度不一时浪费多 | 几乎不浪费 |
选型建议:
- 长度固定用
CHAR:编码、状态、性别、手机号; - 长度变化大用
VARCHAR:用户名、邮箱、标题、地址; VARCHAR(255)是最常用的”万金油”长度,大部分短文本都够。
Tip别为了”安全”把所有字段都设成
VARCHAR(255)或更长。长度设得太长,虽然实际存的少,但会影响索引(前缀索引)和内存排序缓冲。按业务合理预估长度。
8.5 VARCHAR 的最大长度限制
VARCHAR 的 M 理论最大是 65,535,但实际达不到,因为受行大小限制:
MySQL 一行的所有列加起来不能超过 65,535 字节(不包括 BLOB/TEXT)。
看个例子,utf8mb4 下一个字符最多 4 字节:
-- 这样会失败:一个 VARCHAR 占满了整行
CREATE TABLE bad (
s VARCHAR(16384) -- 16384 × 4 = 65536,超了
) CHARACTER SET utf8mb4;
-- ERROR 1118: Row size too large
而且如果一行有多个 VARCHAR 列,它们加起来也不能超 65,535 字节。如果需要存超长文本,就该用 TEXT 系列。
Note
VARCHAR的数据存在行内,超过 768 字节的部分可能溢出到外部页。这影响 InnoDB 的存储效率,所以超长字段别用VARCHAR,用TEXT。
8.6 TEXT 系列:长文本专用
TEXT 是专门存长文本的类型,有四个档位:
| 类型 | 最大长度 | 用途 |
|---|---|---|
TINYTEXT | 255 字节 | 极短文本 |
TEXT | 65,535 字节 | 普通长文本,约 64 KB |
MEDIUMTEXT | 16,777,215 字节 | 中等文本,约 16 MB |
LONGTEXT | 4,294,967,295 字节 | 大文本,约 4 GB |
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200),
content MEDIUMTEXT
);
TEXT 和 VARCHAR 的区别
虽然都能存字符,但有几个关键不同:
- 存储位置:
TEXT内容存在行外(外部页),行内只存指针;VARCHAR存在行内; - 默认值:
TEXT不能有默认值(8.0 前),VARCHAR可以; - 索引:
TEXT建索引必须指定前缀长度,VARCHAR可以全列索引; - 行大小:
TEXT不算进行 65,535 字节限制。
Warning不要拿
TEXT存短内容。用户名、邮箱这种用VARCHAR,TEXT是给”文章正文""商品描述”这种超长文本用的。
8.7 字符串的长度怎么算
这一节是实战。MySQL 提供了两个长度函数:
LENGTH(s):返回字节数;CHAR_LENGTH(s):返回字符数。
utf8mb4 下,中文一个字符占 3~4 字节,英文一个字符占 1 字节:
mysql> SELECT LENGTH('你好'), CHAR_LENGTH('你好');
+----------------+---------------------+
| LENGTH('你好') | CHAR_LENGTH('你好') |
+----------------+---------------------+
| 6 | 2 |
+----------------+---------------------+
‘你好’ 是 2 个字符、6 个字节(utf8mb4 下中文占 3 字节)。
Tip判断字符串长度时,要用
CHAR_LENGTH不是LENGTH。LENGTH数的是字节,中文会数成好几个,容易判断错。
8.8 ENUM 和 SET(下节细讲)
ENUM 和 SET 也是字符串类型,但用法特殊:
ENUM('a','b','c'):枚举,只能取列表里的一个值;SET('a','b','c'):集合,能取列表里的多个值。
比如订单状态 status ENUM('pending','paid','shipped','done')。这两个下一节和 JSON 一起细讲。
8.9 字符串类型选型建议
归纳几条实战经验:
- 定长用 CHAR,变长用 VARCHAR:这是第一原则;
- 短文本用 VARCHAR:用户名
VARCHAR(50)、邮箱VARCHAR(100)、标题VARCHAR(200); - 长文本用 TEXT 系列:按预估大小选档,文章用
MEDIUMTEXT,超大的用LONGTEXT; - 状态码用 CHAR(1) 或 ENUM:别用
VARCHAR浪费; - 手机号用 CHAR(11):定长,且不要参与数值运算;
- 别滥用超大长度:
VARCHAR(255)够用就别写VARCHAR(5000); - 判断长度用 CHAR_LENGTH:数字符不数字节。
8.10 一个建表示例
把这一节学的串起来,建个规范的 users 表:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
phone CHAR(11),
age TINYINT UNSIGNED,
bio VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
username/email/bio变长,用VARCHAR;phone固定 11 位,用CHAR(11);age用TINYINT UNSIGNED;- 字符集统一
utf8mb4。
8.11 小结
这一节掌握了字符串类型:
CHAR(M)定长,补空格、取时去空格,适合固定长度;VARCHAR(M)变长,保留尾部空格,适合长度变化大的文本;VARCHAR受行 65,535 字节限制,超长用TEXT;TEXT四档:TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT,存行外;LENGTH数字节,CHAR_LENGTH数字符,判断长度用后者;- 选型核心:定长用 CHAR、变长用 VARCHAR、超长用 TEXT。
下一节讲日期与时间类型,这是另一类容易出错的数据类型。