MySQL 文本数据类型(CHAR/VARCHAR/TEXT/BLOB):区别、场景与实战
你在日常MySQL表设计中,是不是经常纠结:存储用户名该用CHAR还是VARCHAR?存储文章内容该选TEXT还是BLOB?不同文本类数据类型的存储特性、空间占用差异很大,选不对不仅会浪费存储空间,还可能影响查询性能。这篇教程会通过理论解析+可运行代码案例,帮你彻底理清它们的区别,掌握精准选择的逻辑。
一、核心数据类型分类与基础定义
先明确我们要对比的四大文本/二进制数据类型:
CHAR(n):固定长度字符串类型,n表示字符长度(默认n=1,取值范围1~255)VARCHAR(n):可变长度字符串类型,n表示字符最大长度(取值范围1~65535,受行长度限制)TEXT:长文本字符串类型,专门存储大量字符数据,分为TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXTBLOB:二进制大对象类型,专门存储二进制数据(如图片、文件、音频等),分为TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB
二、CHAR 与 VARCHAR 深度对比
1. 理论存储特点
| 特性 | CHAR(n) | VARCHAR(n) |
|---|---|---|
| 长度特性 | 固定长度,无论实际存储内容多长,均占用n个字符的空间 | 可变长度,仅占用实际存储内容长度+1~2字节的额外开销 |
| 填充与截断 | 存储时右侧自动填充空格至n长度,查询时自动去除尾部空格 | 不自动填充空格,超出n长度时(严格模式下)报错,宽松模式下截断 |
| 索引效率 | 更高,固定长度便于MySQL快速定位与检索 | 略低,额外的长度标识会增加索引维护成本 |
| 适用场景 | 短字符串、长度固定的数据 | 短/中字符串、长度不固定的数据 |
2. 占用空间规则
-
CHAR(n) 空间计算 :
占用空间 = n × 字符编码字节数(与编码格式强相关)
示例:UTF-8编码下(一个汉字占3字节,英文字母占1字节),
CHAR(10)存储"张三"时,占用空间=10×3=30字节(自动填充8个空格补全10个字符);存储"abc"时,占用空间=10×1=10字节(自动填充7个空格)。 -
VARCHAR(n) 空间计算 :
占用空间 = 实际内容字节数 + 长度标识字节数(1或2字节)
长度标识规则:当n ≤ 255时,用1字节标识长度;当n > 255时,用2字节标识长度。
示例:UTF-8编码下,
VARCHAR(10)存储"张三"时,实际内容字节数=6,长度标识1字节,总占用=7字节;VARCHAR(300)存储"abcdef"时,实际内容字节数=6,长度标识2字节,总占用=8字节。
3. CHAR 与 VARCHAR 实战代码案例
步骤1:创建测试表(区分CHAR与VARCHAR)
sql
-- 创建测试表,指定UTF-8编码
CREATE TABLE char_varchar_test (
id INT PRIMARY KEY AUTO_INCREMENT,
char_col CHAR(10) COMMENT '固定长度字符串列',
varchar_col VARCHAR(10) COMMENT '可变长度字符串列'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- utf8mb4兼容所有Unicode字符(含emoji)
步骤2:插入测试数据
sql
-- 插入相同内容:"MySQL"(5个字符)
INSERT INTO char_varchar_test (char_col, varchar_col)
VALUES ('MySQL', 'MySQL'), ('数据库', '数据库');
-- 插入超出长度的测试数据(验证截断/报错)
-- 先查看sql_mode(严格模式下超出长度会报错)
SELECT @@sql_mode;
-- 若需测试宽松模式,临时修改sql_mode
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';
-- 插入15个字符的内容(超出n=10的限制)
INSERT INTO char_varchar_test (char_col, varchar_col)
VALUES ('1234567890abcde', '1234567890abcde');
步骤3:查询数据并验证长度与空间
sql
-- 1. 查询存储的内容
SELECT id, char_col, varchar_col FROM char_varchar_test;
-- 2. 验证CHAR的尾部空格自动去除(使用LENGTH函数查看字节长度)
SELECT
id,
CHAR_LENGTH(char_col) AS char_char_len, -- 字符长度
LENGTH(char_col) AS char_byte_len, -- 字节长度(UTF8MB4下,英文1字节,中文4字节)
CHAR_LENGTH(varchar_col) AS varchar_char_len,
LENGTH(varchar_col) AS varchar_byte_len
FROM char_varchar_test;
步骤4:结果分析
- 对于"MySQL"(5个字符):
char_col(CHAR(10)):字符长度=5(查询时去除了填充的5个空格),字节长度=10(存储时占用10×1=10字节)varchar_col(VARCHAR(10)):字符长度=5,字节长度=5+1=6(实际内容5字节+1字节长度标识)
- 对于"数据库"(3个中文字符):
char_col:字节长度=10×4=40字节(固定占用)varchar_col:字节长度=3×4+1=13字节(实际内容12字节+1字节长度标识)
- 超出长度的内容:宽松模式下会被截断为10个字符,严格模式下直接报错。
三、TEXT 与 BLOB 深度对比
1. 理论定义差异
| 特性 | TEXT | BLOB |
|---|---|---|
| 数据类型 | 字符类型,存储文本数据(字符串) | 二进制类型,存储二进制数据(无字符语义) |
| 字符编码 | 受表/列字符编码控制(如UTF8MB4) | 无编码概念,直接存储原始二进制字节流 |
| 排序与比较 | 按字符编码的规则进行排序、比较 | 按二进制字节值进行排序、比较 |
| 函数支持 | 支持字符串函数(如CONCAT、SUBSTR) | 不支持字符串函数,需转换为字符类型后使用 |
| 存储上限 | TINYTEXT(255)、TEXT(65535)、MEDIUMTEXT(16M)、LONGTEXT(4G) | 与TEXT对应,TINYBLOB(255)、BLOB(65535)、MEDIUMBLOB(16M)、LONGBLOB(4G) |
2. TEXT/BLOB 与 CHAR/VARCHAR 的核心区别
CHAR/VARCHAR的数据直接存储在表的行(row)中,访问速度更快;TEXT/BLOB的数据(超出一定长度后)会被存储在行外的独立存储空间,行中仅保存指向该存储空间的指针,访问速度相对较慢;CHAR/VARCHAR支持默认值,TEXT/BLOB不支持默认值(MySQL语法限制)。
3. TEXT 与 BLOB 实战代码案例
步骤1:创建测试表(区分TEXT与BLOB)
sql
-- 创建TEXT与BLOB测试表
CREATE TABLE text_blob_test (
id INT PRIMARY KEY AUTO_INCREMENT,
tiny_text_col TINYTEXT COMMENT '小型文本(最大255字符)',
text_col TEXT COMMENT '普通文本(最大65535字符)',
tiny_blob_col TINYBLOB COMMENT '小型二进制对象(最大255字节)',
blob_col BLOB COMMENT '普通二进制对象(最大65535字节)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
步骤2:插入测试数据
sql
-- 1. 插入文本数据到TEXT列
INSERT INTO text_blob_test (tiny_text_col, text_col)
VALUES (
'这是TINYTEXT存储的短文本',
'这是TEXT存储的较长文本,可用于存储文章内容、商品描述等。
支持换行、特殊字符,最大存储长度为65535个字符(UTF8MB4下对应约16KB字节)。
后续可以通过字符串函数对其进行截取、拼接等操作。'
);
-- 2. 插入二进制数据到BLOB列(以图片文件为例,也可插入字符串的二进制形式)
-- 方式1:插入字符串的二进制字节流
INSERT INTO text_blob_test (tiny_blob_col, blob_col)
VALUES (
UNHEX('6162636465'), -- 二进制数据:abcde(十六进制表示)
LOAD_FILE('/tmp/test_image.png') -- 方式2:加载本地图片文件(需MySQL有权限访问该路径)
) WHERE id = 1; -- 关联上述记录
步骤3:查询与操作数据
sql
-- 1. 查询TEXT列数据(正常显示文本)
SELECT id, tiny_text_col, text_col FROM text_blob_test;
-- 2. 查询BLOB列数据(显示二进制字节流,需转换后查看)
SELECT
id,
HEX(tiny_blob_col) AS tiny_blob_hex, -- 转换为十六进制显示
LENGTH(tiny_blob_col) AS tiny_blob_byte_len,
LENGTH(blob_col) AS blob_byte_len
FROM text_blob_test;
-- 3. TEXT列支持字符串函数操作
SELECT
id,
SUBSTR(text_col, 1, 20) AS text_substr, -- 截取前20个字符
CHAR_LENGTH(text_col) AS text_char_len
FROM text_blob_test;
-- 4. BLOB列不支持字符串函数(验证报错)
SELECT CONCAT(tiny_blob_col, '附加文本') FROM text_blob_test;
步骤4:结果分析
TEXT列:正常显示中文文本,可直接使用SUBSTR、CHAR_LENGTH等字符串函数;BLOB列:直接查询显示为乱码(二进制流),需通过HEX()转换为可读格式,无法直接使用字符串函数;TINYTEXT/TINYBLOB:最大存储长度255(字符/字节),TEXT/BLOB最大存储长度65535(字符/字节)。
四、文本数据类型选择逻辑(核心总结)
遵循"最小够用+匹配场景"的原则,优先级从高到低(性能最优→功能适配):
1. 优先选择 CHAR(n) 的场景
- 数据长度固定不变:如手机号(11位)、身份证号(18位)、邮编、性别(男/女)、状态码(0/1/2);
- 数据长度很短(一般n≤20):如用户名(固定长度限制)、密码(加密后长度固定);
- 对查询性能要求极高:如索引列、频繁排序/分组的列(CHAR的固定长度提升索引效率)。
- 示例:
user_mobile CHAR(11)、user_gender CHAR(1)。
2. 优先选择 VARCHAR(n) 的场景
- 数据长度不固定:如用户名(长度1~16位)、标题、地址、备注等;
- 数据长度较短/中等(一般不超过1000字符):兼顾存储空间与查询性能;
- 需节省存储空间:VARCHAR仅占用实际内容空间,比CHAR更节省磁盘I/O。
- 示例:
article_title VARCHAR(200)、user_address VARCHAR(500)。
3. 优先选择 TEXT 的场景
- 存储大量文本数据:如文章内容、商品详情、评论内容、日志信息等;
- 数据长度超过VARCHAR上限(65535字符):如长篇小说、批量日志;
- 无需设置默认值,且对查询性能要求不极致(可通过索引优化)。
- 示例:
article_content TEXT、system_log LONGTEXT(超大数据用LONGTEXT)。
4. 优先选择 BLOB 的场景
- 存储二进制数据:如图片、音频、视频、PDF文件、压缩包等;
- 无需字符编码转换,需保存原始字节流:如用户上传的头像图片、附件文件;
- 示例:
user_avatar BLOB、file_attachment MEDIUMBLOB(大文件用MEDIUMBLOB/LONGBLOB)。
五、完整可运行代码汇总
sql
-- =============================================
-- 1. CHAR 与 VARCHAR 测试
-- =============================================
-- 创建表
CREATE TABLE char_varchar_test (
id INT PRIMARY KEY AUTO_INCREMENT,
char_col CHAR(10) COMMENT '固定长度字符串列',
varchar_col VARCHAR(10) COMMENT '可变长度字符串列'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入数据
INSERT INTO char_varchar_test (char_col, varchar_col)
VALUES ('MySQL', 'MySQL'), ('数据库', '数据库');
-- 临时修改为宽松模式(可选)
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';
-- 插入超出长度数据
INSERT INTO char_varchar_test (char_col, varchar_col)
VALUES ('1234567890abcde', '1234567890abcde');
-- 查询与验证
SELECT id, char_col, varchar_col FROM char_varchar_test;
SELECT
id,
CHAR_LENGTH(char_col) AS char_char_len,
LENGTH(char_col) AS char_byte_len,
CHAR_LENGTH(varchar_col) AS varchar_char_len,
LENGTH(varchar_col) AS varchar_byte_len
FROM char_varchar_test;
-- =============================================
-- 2. TEXT 与 BLOB 测试
-- =============================================
-- 创建表
CREATE TABLE text_blob_test (
id INT PRIMARY KEY AUTO_INCREMENT,
tiny_text_col TINYTEXT COMMENT '小型文本(最大255字符)',
text_col TEXT COMMENT '普通文本(最大65535字符)',
tiny_blob_col TINYBLOB COMMENT '小型二进制对象(最大255字节)',
blob_col BLOB COMMENT '普通二进制对象(最大65535字节)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入TEXT数据
INSERT INTO text_blob_test (tiny_text_col, text_col)
VALUES (
'这是TINYTEXT存储的短文本',
'这是TEXT存储的较长文本,可用于存储文章内容、商品描述等。
支持换行、特殊字符,最大存储长度为65535个字符(UTF8MB4下对应约16KB字节)。
后续可以通过字符串函数对其进行截取、拼接等操作。'
);
-- 插入BLOB数据
UPDATE text_blob_test
SET
tiny_blob_col = UNHEX('6162636465'),
blob_col = UNHEX('6D7973716C5F626C6F62') -- 对应字符串mysql_blob
WHERE id = 1;
-- 查询数据
SELECT id, tiny_text_col, text_col FROM text_blob_test;
SELECT
id,
HEX(tiny_blob_col) AS tiny_blob_hex,
LENGTH(tiny_blob_col) AS tiny_blob_byte_len,
LENGTH(blob_col) AS blob_byte_len
FROM text_blob_test;
-- TEXT字符串函数操作
SELECT id, SUBSTR(text_col, 1, 20) AS text_substr, CHAR_LENGTH(text_col) AS text_char_len FROM text_blob_test;
-- =============================================
-- 3. 清理测试表(可选)
-- =============================================
DROP TABLE IF EXISTS char_varchar_test;
DROP TABLE IF EXISTS text_blob_test;
总结
CHAR是固定长度,快但费空间;VARCHAR是可变长度,省空间但性能略低,二者均适用于短文本;TEXT存储长文本(有字符编码),支持字符串函数;BLOB存储二进制数据(无编码),不支持字符串函数,二者均适用于大数据量存储;- 选择逻辑:先判断长度是否固定(固定用CHAR,不固定用VARCHAR),再判断是否超过VARCHAR上限(超过用TEXT/BLOB),最后根据数据类型(文本用TEXT,二进制用BLOB)精准选择。