MySQL | 文本数据类型(CHAR/VARCHAR/TEXT/BLOB):区别、场景与实战

MySQL 文本数据类型(CHAR/VARCHAR/TEXT/BLOB):区别、场景与实战

你在日常MySQL表设计中,是不是经常纠结:存储用户名该用CHAR还是VARCHAR?存储文章内容该选TEXT还是BLOB?不同文本类数据类型的存储特性、空间占用差异很大,选不对不仅会浪费存储空间,还可能影响查询性能。这篇教程会通过理论解析+可运行代码案例,帮你彻底理清它们的区别,掌握精准选择的逻辑。

一、核心数据类型分类与基础定义

先明确我们要对比的四大文本/二进制数据类型:

  1. CHAR(n):固定长度字符串类型,n 表示字符长度(默认n=1,取值范围1~255)
  2. VARCHAR(n):可变长度字符串类型,n 表示字符最大长度(取值范围1~65535,受行长度限制)
  3. TEXT:长文本字符串类型,专门存储大量字符数据,分为TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT
  4. BLOB:二进制大对象类型,专门存储二进制数据(如图片、文件、音频等),分为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 列:正常显示中文文本,可直接使用SUBSTRCHAR_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 TEXTsystem_log LONGTEXT(超大数据用LONGTEXT)。

4. 优先选择 BLOB 的场景

  • 存储二进制数据:如图片、音频、视频、PDF文件、压缩包等;
  • 无需字符编码转换,需保存原始字节流:如用户上传的头像图片、附件文件;
  • 示例:user_avatar BLOBfile_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;

总结

  1. CHAR 是固定长度,快但费空间;VARCHAR 是可变长度,省空间但性能略低,二者均适用于短文本;
  2. TEXT 存储长文本(有字符编码),支持字符串函数;BLOB 存储二进制数据(无编码),不支持字符串函数,二者均适用于大数据量存储;
  3. 选择逻辑:先判断长度是否固定(固定用CHAR,不固定用VARCHAR),再判断是否超过VARCHAR上限(超过用TEXT/BLOB),最后根据数据类型(文本用TEXT,二进制用BLOB)精准选择。
相关推荐
悄悄敲敲敲2 小时前
MySQL内置函数
数据库·mysql
小北方城市网2 小时前
第 5 课:后端工程化进阶 ——Python 分层架构 + 中间件 + 日志 / 异常统一处理(打造企业级高可用后端)
数据库·人工智能·python·mysql·数据库架构
m0_598177232 小时前
SQL(5)- 事务
java·数据库·sql
郝学胜-神的一滴2 小时前
Qt重复添加控件问题探析:现象、原理与解决方案
开发语言·数据库·c++·qt·程序人生
星空椰2 小时前
Windows 安装 Oracle 19c Instant Client
数据库·windows·oracle
万象.2 小时前
redis通用命令与数据结构
数据结构·数据库·redis
西柚小萌新2 小时前
【大模型:RAG】--向量数据库Milvus详解2
数据库·milvus
小北方城市网2 小时前
第 4 课:前端工程化进阶 ——Vue 核心语法 + 组件化开发(前端能力质的飞跃)
大数据·开发语言·数据库·python·状态模式·数据库架构
嵌入式×边缘AI:打怪升级日志2 小时前
USB设备枚举过程详解:从插入到正常工作
开发语言·数据库·笔记