字符串类型
导学
字符串是数据库中最常见的数据类型之一。MySQL 5.7 提供多种字符串类型,选错会导致空间浪费、查询变慢,甚至数据截断。本节讲透每种类型的适用场景。
定义
字符串类型:用于存储文本数据的数据类型。MySQL 5.7 主要提供 CHAR、VARCHAR、TEXT、BLOB 及其变体。
CHAR vs VARCHAR
| 特性 | CHAR(M) | VARCHAR(M) |
|---|---|---|
| 存储方式 | 定长,不足补空格 | 变长,只存实际内容 + 1~2 字节长度前缀 |
| 最大长度 | 255 字符 | 65535 字节(受行大小限制) |
| 检索效率 | 固定长度,略快 | 需读取长度前缀,略慢 |
| 空间效率 | 短数据浪费空间 | 按需存储,节省空间 |
| 尾部空格 | 存储时补足,检索时去除 | 保留尾部空格(5.7 行为) |
存储差异演示
当前数据状态:
创建两张结构相同但类型不同的表:
CREATE TABLE char_demo (
id INT PRIMARY KEY,
code CHAR(10)
);
CREATE TABLE varchar_demo (
id INT PRIMARY KEY,
code VARCHAR(10)
);
INSERT INTO char_demo VALUES
(1, 'ABC');
INSERT INTO varchar_demo VALUES
(1, 'ABC');
验证存储差异:
SELECT
id,
code,
LENGTH(code) AS length_val,
CHAR_LENGTH(code) AS char_length_val
FROM char_demo;
结果:
| id | code | length_val | char_length_val |
|---|---|---|---|
| 1 | ABC | 3 | 3 |
SELECT
id,
code,
LENGTH(code) AS length_val,
CHAR_LENGTH(code) AS char_length_val
FROM varchar_demo;
结果:
| id | code | length_val | char_length_val |
|---|---|---|---|
| 1 | ABC | 3 | 3 |
结果解读:表面上检索出来的长度相同,是因为 CHAR 在检索时会自动去除尾部空格。如果插入时带有尾部空格,差异就会显现:
INSERT INTO char_demo VALUES (2, 'XYZ ');
INSERT INTO varchar_demo VALUES (2, 'XYZ ');
SELECT
id,
CONCAT('[', code, ']') AS wrapped_code,
LENGTH(code) AS stored_length
FROM char_demo WHERE id = 2;
结果:
| id | wrapped_code | stored_length |
|---|---|---|
| 2 | [XYZ] | 3 |
SELECT
id,
CONCAT('[', code, ']') AS wrapped_code,
LENGTH(code) AS stored_length
FROM varchar_demo WHERE id = 2;
结果:
| id | wrapped_code | stored_length |
|---|---|---|
| 2 | [XYZ ] | 6 |
结果解读:
CHAR(10)存储'XYZ '时,检索时尾部空格被去除,显示为[XYZ],长度 3VARCHAR(10)存储'XYZ '时,保留尾部空格,显示为[XYZ ],长度 6- 这说明
CHAR在存储时确实补了空格,只是在返回给客户端时去除了
SQL 建表示例
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
dept VARCHAR(20),
score DECIMAL(5,2)
);
INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);
当前表数据:
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
选型建议:
- 长度固定或几乎固定:
CHAR(如手机号、MD5 值、性别标志) - 长度变化大:
VARCHAR(如姓名、地址、邮箱) - 最大长度:绝大部分场景用
VARCHAR,CHAR只在明确定长时有优势
TEXT 类型家族
| 类型 | 最大长度 | 存储方式 |
|---|---|---|
TINYTEXT | 255 字节 | 内联或溢出存储 |
TEXT | 65535 字节 | 溢出存储(单独页) |
MEDIUMTEXT | 16 MB | 溢出存储 |
LONGTEXT | 4 GB | 溢出存储 |
TEXT 与 VARCHAR 对比演示
当前数据状态:
CREATE TABLE article_text (
article_id INT PRIMARY KEY,
summary VARCHAR(255) COMMENT '摘要,较短',
content TEXT COMMENT '正文,可能很长'
);
INSERT INTO article_text VALUES
(1, 'MySQL简介', 'MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL是最好的RDBMS应用软件之一。');
操作语句:
SELECT
article_id,
summary,
LENGTH(summary) AS summary_bytes,
LEFT(content, 50) AS content_preview,
LENGTH(content) AS content_bytes
FROM article_text;
操作后的数据状态:
| article_id | summary | summary_bytes | content_preview | content_bytes |
|---|---|---|---|---|
| 1 | MySQL简介 | 15 | MySQL是一个关系型数据库管理系统,由瑞典MySQL... | 137 |
结果解读:
summary使用VARCHAR(255),数据内联存储在行中,查询速度快content使用TEXT,当数据较大时存储在独立的溢出页中,需要额外的 I/O 读取TEXT列不能完全利用内存中的行缓存,且某些操作(如内存排序)受限
关键认知:
TEXT列的数据通常存储在独立的溢出页中,不在行内。这会影响查询性能(需要额外的 I/O),且TEXT列不能完全利用内存中的行缓存。
BLOB 类型家族
BLOB(Binary Large Object)用于存储二进制数据,如图片、音频、文件等。类型与 TEXT 一一对应(TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB)。
重要建议:MySQL 可以存图片,但不建议。更好的做法是在 MySQL 中存文件路径,将实际文件存放在对象存储(OSS、S3)或文件系统中。
存路径 vs 存文件的对比演示
当前数据状态:
-- 不推荐:直接存图片
CREATE TABLE bad_design (
image_id INT PRIMARY KEY,
image_name VARCHAR(100),
image BLOB -- 图片塞进数据库,表膨胀,备份缓慢
);
-- 推荐:存文件路径
CREATE TABLE good_design (
image_id INT PRIMARY KEY,
image_name VARCHAR(100),
image_url VARCHAR(500) -- 如 https://cdn.example.com/img/123.jpg
);
INSERT INTO good_design VALUES
(1, 'logo.png', 'https://cdn.example.com/img/logo.png'),
(2, 'banner.jpg', 'https://cdn.example.com/img/banner.jpg');
当前 good_design 表数据:
| image_id | image_name | image_url |
|---|---|---|
| 1 | logo.png | https://cdn.example.com/img/logo.png |
| 2 | banner.jpg | https://cdn.example.com/img/banner.jpg |
结果解读:存 URL 的优势:
- 数据库备份和恢复速度不受影响
- 图片可通过 CDN 分发,降低数据库负载
- 对象存储成本通常低于数据库存储成本
- 数据库只负责元数据管理,职责清晰
常见误区
| 误区 | 正解 |
|---|---|
VARCHAR 比 CHAR 慢很多 | 现代 MySQL 中差异极小,VARCHAR 的空间节省通常更有价值。 |
TEXT 和 VARCHAR 没区别 | TEXT 数据通常存在溢出页,查询需要额外 I/O;且 TEXT 有某些索引限制。 |
| 字符串长度以字节计 | VARCHAR(10) 在 utf8mb4 下最多存 10 个字符(可能占 40 字节),不是 10 字节。 |
VARCHAR 声明越大越好 | 过大的声明会浪费内存(排序缓冲区按声明长度分配),且可能触发行大小限制。 |
面试考点
Q:CHAR 和 VARCHAR 的区别?
CHAR定长,存储时不足长度补空格,适合长度固定的场景;VARCHAR变长,只存实际内容加长度前缀,适合长度变化大的场景。MySQL 5.7 中绝大多数场景优先用VARCHAR。
Q:VARCHAR(255) 有什么特殊意义?
VARCHAR(255)及以下使用 1 字节存储长度前缀;VARCHAR(256)及以上需要 2 字节。但这不是选择 255 的理由,应按实际业务需求声明长度。
Q:为什么不在数据库里存图片?
- 数据库备份和恢复时间暴增;2. 图片读写会污染缓冲池,影响正常查询性能;3. 对象存储(OSS/S3)成本更低、CDN 分发更快。数据库只存文件元数据和 URL。
小结
- 短文本、定长文本用
CHAR,变长文本用VARCHAR - 长文本(> 65535 字节)用
TEXT,二进制数据用BLOB TEXT/BLOB通常存储在溢出页,查询性能差于VARCHAR- 图片/文件应存 URL,不存数据库
下一章引子:除了文本,业务中另一类高频数据是日期和时间——注册时间、订单时间、有效期等。