MySQL 数据库支持多种字符串类型,如下表:
| 类型 | 长度 | 空间利用率 | 索引性能 | 适用场景 |
|---|---|---|---|---|
| CHAR | 固定短 | 差 | 极好 | 身份证、手机号、固定编码 |
| VARCHAR | 可变中等 | 优秀 | 优秀 | 名称、地址、短文本(主流) |
| TEXT | 超长文本 | 一般 | 差 | 商品详情、富文本长内容 |
| ENUM | 固定少数值 | 极高 | 好 | 固定不变业务状态 |
| VARBINARY | 二进制 | 可变 | 一般 | 加密字符串、哈希值 |
| BLOB | 二进制文件 | 差 | 极差 | 禁止存图片文件,仅存 URL |
下面将仔细介绍上面的各个分类:
CHAR 和 VARCHAR 是最常用的字符串类型,它们的区别需要理解清楚:
CHAR(n):固定占用 n 个字符的空间,不足 n 个会在右侧填充空格。查询时会自动去掉尾部空格(MySQL 8.0之前)或保留(MySQL 8.0 之后行为有变化)
VARCHAR(n):实际占用空间是内容长度+1 或 2 字节(用于存储长度),最大 65535 字节。
例如:创建表,演示 char 和 varchar 的区别。
-- 创建数据表
mysql> CREATE TABLE char_varchar_demo (
-> char_col CHAR(10) COMMENT '定长字符串',
-> varchar_col VARCHAR(10) COMMENT '变长字符串'
-> );
Query OK, 0 rows affected (0.01 sec)
-- 插入数据
mysql> INSERT INTO char_varchar_demo VALUES ('abc', 'abc');
Query OK, 1 row affected (0.00 sec)
-- 查看长度
mysql> SELECT
-> char_col,
-> LENGTH(char_col) AS char_length,
-> varchar_col,
-> LENGTH(varchar_col) AS varchar_length
-> FROM char_varchar_demo;
+----------+-------------+-------------+----------------+
| char_col | char_length | varchar_col | varchar_length |
+----------+-------------+-------------+----------------+
| abc | 3 | abc | 3 |
+----------+-------------+-------------+----------------+
1 row in set (0.00 sec)上面输出中,char_length 是实际字符串的长度,而不是创建表时声明的 10。
那么,我们该如何进行选择?
使用 CHAR 的场景:
长度固定的数据:手机号(11位)、身份证号(18位)、邮编、MD5值(32位)
经常变更的数据:用户名(如果限制固定长度)
非常短的字符串:性别('M'/'F')、是否标记('Y'/'N')
使用 VARCHAR 的场景:
长度变化大的数据:姓名、地址、商品标题
大多数业务场景
注意:在 MySQL 5.7 及之前,CHAR 在存储时会去掉尾部空格,这可能导致意外:
-- 在 MySQL 5.7 中
INSERT INTO char_varchar_demo (char_col) VALUES ('abc '); -- 带空格
SELECT CONCAT('[', char_col, ']') FROM char_varchar_demo; -- 输出[abc],空格被去掉了MySQL 8.0 改进了这个行为,但为了兼容,建议尽量避免依赖这个特性。
当字符串超过 VARCHAR 的容量时,需要使用 TEXT 类型。例如,存储博客的文章内容,存储商品介绍信息等等。
TEXT 类型的特点如下:
有独立的存储区域,主表只存指针,查询时会产生额外的 IO
不能在 TEXT 列上创建普通索引(可以创建前缀索引)
不能设置默认值(MySQL 8.0.13 之前)
示例:
-- 创建数据表
mysql> CREATE TABLE text_demo (
-> tiny TINYTEXT COMMENT '最大255字节',
-> txt TEXT COMMENT '最大65535字节,约64KB',
-> medium MEDIUMTEXT COMMENT '最大16MB',
-> longtxt LONGTEXT COMMENT '最大4GB'
-> );
Query OK, 0 rows affected (0.01 sec)
-- 插入较长的文本
mysql> INSERT INTO text_demo (txt) VALUES (
-> '这是一段很长的文本...(超过255字符)'
-> );
Query OK, 1 row affected (0.00 sec)
mysql> select * from text_demo;
+------+-----------------------------------------------------+--------+---------+
| tiny | txt | medium | longtxt |
+------+-----------------------------------------------------+--------+---------+
| NULL | 这是一段很长的文本...(超过255字符) | NULL | NULL |
+------+-----------------------------------------------------+--------+---------+
1 row in set (0.00 sec)使用建议:
TINYTEXT:短描述、摘要(255字节约80多个汉字)
TEXT:商品详情、文章内容、评论(一般够用了)
MEDIUMTEXT:长篇文章、HTML 页面源码
LONGTEXT:极少使用,大文件存储建议用对象存储(OSS/S3)
BLOB用于存储二进制数据,如存放图片内容等,示例:
-- 创建数据表
CREATE TABLE blob_demo (
id INT PRIMARY KEY,
image MEDIUMBLOB COMMENT '图片数据'
);但现代应用中,通常不建议把图片、文件直接存数据库,而是:
文件上传到对象存储(阿里云OSS、AWS S3等)
数据库只存文件的URL或路径
这样做的好处是:减轻数据库负担、方便 CDN 加速、降低备份复杂度。
ENUM 是枚举类型,允许从提供的枚举值中任意选择一个。SET 是集合类型,允许用户在提供的可选值中选择多个。例如:
-- 创建数据表
mysql> CREATE TABLE enum_set_demo (
-> gender ENUM('male', 'female', 'unknown') DEFAULT 'unknown' COMMENT '性别',
-> hobbies SET('reading', 'sports', 'music', 'travel') COMMENT '爱好可多选'
-> );
Query OK, 0 rows affected (0.03 sec)
-- 插入数据
mysql> INSERT INTO enum_set_demo VALUES ('male', 'reading,sports');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO enum_set_demo VALUES ('female', 'music,travel');
Query OK, 1 row affected (0.00 sec)
-- 查询
mysql> SELECT * FROM enum_set_demo WHERE hobbies LIKE '%sports%';
+--------+----------------+
| gender | hobbies |
+--------+----------------+
| male | reading,sports |
+--------+----------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM enum_set_demo WHERE FIND_IN_SET('reading', hobbies) > 0;
+--------+----------------+
| gender | hobbies |
+--------+----------------+
| male | reading,sports |
+--------+----------------+
1 row in set (0.00 sec)上面查询语句中,第一个查询语句把 SET 字段当成普通字符串做模糊匹配,只要字段文本里包含 sports 子串就命中。操作简单,但是存在误匹配风险,如果存在相似选项会查错,例如,假设集合新增 e-sports,数据值 e-sports,LIKE '%sports%' 也会匹配到,逻辑错误。同时 LIKE 无法利用索引,全表扫描性能差。
第二个查询语句,使用了 FIND_IN_SET(目标值, SET字段) 函数,这是专门为 SET 类型设计的内置函数,精准匹配集合内完整独立项,不会出现子串误匹配。返回值规则:
找到目标:返回该选项在集合定义里的序号(≥1)
没找到:返回 0
查询语句中的 >0 代表“包含该爱好”。
使用建议:
ENUM 适合固定选项少的场景,如状态、类型等
但 ENUM 扩展性差,新增选项需要修改表结构
现代开发中,很多人更倾向于用 TINYINT 加代码映射,或使用单独的码表
SET 使用场景更少,多数情况下用关联表更合适
更多知识请阅读后续章节……谢谢!!!