MySQL 字符串类型

🎉摘要:本文详细解析MySQL支持的多种字符串数据类型,包括CHAR、VARCHAR、TEXT、BLOB、ENUM和SET。通过对比长度、空间利用率、索引性能和适用场景,提供具体选择建议和SQL示例,帮助开发者根据业务需求(如固定编码、变长文本、二进制数据、枚举值)高效选择和使用合适的字符串类型。

MySQL 数据库支持多种字符串类型,如下表:

类型长度空间利用率索引性能适用场景
CHAR固定短极好身份证、手机号、固定编码
VARCHAR可变中等优秀优秀名称、地址、短文本(主流)
TEXT超长文本一般商品详情、富文本长内容
ENUM固定少数值极高固定不变业务状态
VARBINARY二进制可变一般加密字符串、哈希值
BLOB二进制文件极差禁止存图片文件,仅存 URL

下面将仔细介绍上面的各个分类:

CHAR 与 VARCHAR 的选择

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 改进了这个行为,但为了兼容,建议尽量避免依赖这个特性。

TEXT类型家族

当字符串超过 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类型

BLOB用于存储二进制数据,如存放图片内容等,示例:

-- 创建数据表
CREATE TABLE blob_demo (
    id INT PRIMARY KEY,
    image MEDIUMBLOB COMMENT '图片数据'
);

但现代应用中,通常不建议把图片、文件直接存数据库,而是:

  • 文件上传到对象存储(阿里云OSS、AWS S3等)

  • 数据库只存文件的URL或路径

这样做的好处是:减轻数据库负担、方便 CDN 加速、降低备份复杂度。

ENUM 和 SET类型

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 使用场景更少,多数情况下用关联表更合适

更多知识请阅读后续章节……谢谢!!!

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号