MySQL 数据类型
一、核心目标
- 理解数据库中"实体、表、记录、字段、属性"之间的对应关系。
- 掌握 MySQL 常用数据类型的分类。
- 能根据数据的取值范围、长度、精度和使用场景选择合适的数据类型。
- 重点掌握
CHAR、VARCHAR、TEXT之间的区别,以及常见日期时间类型的使用。
二、基础概念
在面向对象设计与数据库设计中,可以建立如下对应关系:
| 面向对象概念 | 数据库概念 |
|---|---|
| 类 | 实体 / 表 |
| 对象实例 | 一条记录 / 数据行 |
| 属性 | 字段 / 列 |
| 属性值 | 字段中保存的数据 |
定义表字段时,通常需要确定三件事:
- 字段名称;
- 字段的数据类型;
- 字段的长度、精度或其他约束。
MySQL 常用数据类型可分为四类:
- 数值类型
- 字符串类型
- 二进制类型
- 日期时间类型
三、数值类型
3.1 整数类型
| 类型 | 存储空间 | 有符号范围 | 无符号范围 |
|---|---|---|---|
TINYINT |
1 字节 | -128 ~ 127 | 0 ~ 255 |
SMALLINT |
2 字节 | -32768 ~ 32767 | 0 ~ 65535 |
MEDIUMINT |
3 字节 | -8388608 ~ 8388607 | 0 ~ 16777215 |
INT / INTEGER |
4 字节 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
BIGINT |
8 字节 | -2^63 ~ 2^63-1 |
0 ~ 2^64-1 |
记忆规律
整数类型每增加 1 个字节,能够表示的二进制位数就增加 8 位。
对于占用 n 位的整数:
- 有符号范围:
-2^(n-1)~2^(n-1)-1 - 无符号范围:
0~2^n-1
使用建议
- 年龄、状态值:可考虑
TINYINT - 数量较小的编号:可考虑
SMALLINT - 常规主键、数量、计数:常用
INT - 数据量极大的主键、流水号:可考虑
BIGINT - 字段不需要负数时,可以使用
UNSIGNED
示例:
sql
CREATE TABLE product (
id BIGINT UNSIGNED PRIMARY KEY,
stock INT UNSIGNED,
status TINYINT
);
3.2 位类型与布尔类型
BIT[(M)]
- 位值类型。
M表示每个值占用的位数。M的范围为 1~64。- 省略
M时,默认长度为 1 位。
示例:
sql
is_enabled BIT(1)
BOOL
BOOL是TINYINT(1)的同义写法。0通常表示假。- 非
0值通常表示真。
示例:
sql
is_deleted BOOL DEFAULT FALSE
3.3 浮点数与定点数
| 类型 | 存储空间 | 特点 |
|---|---|---|
FLOAT[(M,D)] |
4 字节 | 单精度浮点数,约可保证 7 位十进制有效精度 |
DOUBLE[(M,D)] |
8 字节 | 双精度浮点数,约可保证 15 位十进制有效精度 |
DECIMAL[(M,D)] |
动态 | 定点数,适合要求精确计算的数据 |
其中:
M:总位数D:小数位数DECIMAL的M最大为 65DECIMAL的D最大为 30- 省略
M时,默认值为 10 - 省略
D时,默认值为 0 M不计算小数点和负号
示例:
sql
price DECIMAL(10, 2)
该字段最多保存 10 位数字,其中小数部分占 2 位,例如:
text
12345678.90
选择原则
- 科学计算、允许近似误差:
FLOAT或DOUBLE - 金额、财务、精确比例:优先使用
DECIMAL - 不应使用浮点数直接保存要求绝对精确的金额
四、字符串与二进制类型
4.1 常见字符串类型
| 类型 | 特点 | 最大长度 |
|---|---|---|
CHAR[(M)] |
固定长度字符串 | 255 个字符 |
VARCHAR(M) |
可变长度字符串 | 最大受行大小和字符集影响,声明上限可到 65535 |
TINYTEXT |
小文本 | 255 字节 |
TEXT |
文本 | 65535 字节 |
MEDIUMTEXT |
中文本 | 16777215 字节 |
LONGTEXT |
大文本 | 4294967295 字节 |
注意:
CHAR和VARCHAR的长度通常以字符为单位。TEXT系列的容量以字节为单位。- 实际可保存的字符数会受到字符集影响。
- 使用多字节字符集时,一个字符可能占用多个字节。
4.2 常见二进制类型
| 类型 | 特点 | 最大长度 |
|---|---|---|
BINARY[(M)] |
固定长度二进制数据 | 255 字节 |
VARBINARY(M) |
可变长度二进制数据 | 由 M 指定 |
TINYBLOB |
小型二进制数据 | 255 字节 |
BLOB |
二进制数据 | 65535 字节 |
MEDIUMBLOB |
中型二进制数据 | 16777215 字节 |
LONGBLOB |
大型二进制数据 | 4294967295 字节 |
字符串类型与二进制类型的区别
- 字符串类型保存字符,通常受字符集和排序规则影响。
- 二进制类型保存原始字节,比较时更关注每个字节的数值。
- 文本数据适合使用
CHAR、VARCHAR、TEXT。 - 文件内容、哈希字节、加密结果等原始数据可考虑二进制类型。
4.3 ENUM 与 SET
ENUM
sql
ENUM('待支付', '已支付', '已取消')
特点:
- 从预定义列表中选择一个值。
- 还可能保存空字符串或
NULL,具体取决于字段约束和 SQL 模式。 - 最多可定义 65535 个不同元素。
- 内部通常使用整数表示。
适用场景:
- 状态值固定且变化较少。
- 每条记录只能选择一个状态。
SET
sql
SET('读', '写', '删除')
特点:
- 可以从预定义列表中选择零个、一个或多个值。
- 最多可定义 64 个元素。
- 内部通常使用整数位组合表示。
适用场景:
- 一条记录允许同时具备多个固定选项。
对比
| 对比项 | ENUM |
SET |
|---|---|---|
| 可选数量 | 只能选一个 | 可以选多个 |
| 最大元素数 | 65535 | 64 |
| 典型场景 | 单一状态 | 多个标签或权限 |
五、字符集与排序规则
字符串列可以指定字符集和排序规则。
示例:
sql
name VARCHAR(50)
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci
排序规则影响:
- 字符串比较
- 大小写是否敏感
- 重音符号是否敏感
- 排序顺序
二进制风格的排序规则通常以 _bin 结尾,例如:
sql
utf8mb4_bin
这种排序规则更接近按照字符编码值进行比较,常用于要求严格区分大小写或字符差异的场景。
六、CHAR 与 VARCHAR
6.1 核心区别
| 对比项 | CHAR(M) |
VARCHAR(M) |
|---|---|---|
| 长度 | 固定长度 | 可变长度 |
M 的含义 |
固定字符长度 | 最大字符长度 |
| 最大声明长度 | 255 个字符 | 受行大小和字符集限制 |
| 存储方式 | 不足时按固定长度处理 | 按实际数据长度存储 |
| 长度记录 | 通常不需要额外记录实际长度 | 需要额外 1 或 2 字节记录长度 |
| 尾部空格 | 读取时通常会去除尾部填充空格 | 通常保留未被截断的尾部空格 |
| 空间利用率 | 较低 | 较高 |
| 典型性能特点 | 定长数据处理较直接 | 更节省空间 |
6.2 存储示例
sql
CREATE TABLE vc (
v VARCHAR(4),
c CHAR(4)
);
INSERT INTO vc VALUES ('ab ', 'ab ');
SELECT
CONCAT('(', v, ')'),
CONCAT('(', c, ')')
FROM vc;
可能看到的结果:
text
(ab )
(ab)
含义:
VARCHAR中原有的尾部空格仍然可见。CHAR读取时会去掉用于填充的尾部空格。
6.3 选择原则
适合 CHAR 的数据:
- 长度基本固定的数据
- 身份证号
- 学号
- 邮编
- 固定长度摘要值,如 MD5 字符串
- 固定格式的业务编码
适合 VARCHAR 的数据:
- 姓名
- 地址
- 邮箱
- 用户名
- 标题
- 长度变化明显的普通字符串
一句话记忆:
长度固定选
CHAR,长度变化选VARCHAR。
七、VARCHAR 与 TEXT
7.1 主要区别
| 对比项 | VARCHAR |
TEXT |
|---|---|---|
| 适合的数据长度 | 较短或中等长度 | 较长文本 |
| 最大容量 | 受单行总大小、字符集等限制 | TEXT 最大 65535 字节 |
| 索引 | 更适合建立普通索引 | 常使用前缀索引或全文索引 |
| 查询场景 | 经常作为检索条件 | 通常保存正文、描述等内容 |
| 典型性能 | 短文本检索通常更方便 | 大文本处理成本通常更高 |
7.2 选择原则
选择 VARCHAR:
- 数据长度较小或中等。
- 经常作为查询条件。
- 需要建立普通索引。
- 例如用户名、邮箱、标题、手机号。
选择 TEXT:
- 数据内容较长。
- 不经常作为精确检索条件。
- 例如文章正文、长备注、详细说明。
示例:
sql
CREATE TABLE article (
id BIGINT UNSIGNED PRIMARY KEY,
title VARCHAR(200) NOT NULL,
summary VARCHAR(1000),
content LONGTEXT
);
八、日期时间类型
8.1 类型对比
| 类型 | 存储空间 | 主要用途 | 常见格式 |
|---|---|---|---|
TIMESTAMP[(fsp)] |
4 字节 | 时间戳、记录创建或更新时间 | YYYY-MM-DD hh:mm:ss[.fraction] |
DATETIME[(fsp)] |
8 字节 | 日期和时间的组合 | YYYY-MM-DD hh:mm:ss[.fraction] |
DATE |
3 字节 | 只保存日期 | YYYY-MM-DD |
TIME[(fsp)] |
3 字节 | 时间或持续时长 | hh:mm:ss[.fraction] |
YEAR[(4)] |
1 字节 | 四位年份 | YYYY |
8.2 常见范围
| 类型 | 支持范围 |
|---|---|
TIMESTAMP |
约从 1970-01-01 到 2038-01-19 |
DATETIME |
1000-01-01 00:00:00 到 9999-12-31 23:59:59 |
DATE |
1000-01-01 到 9999-12-31 |
TIME |
-838:59:59 到 838:59:59 |
YEAR |
1901 到 2155 |
8.3 fsp:小数秒精度
fsp 用于指定秒的小数部分精度:
- 范围:0~6
0:没有小数秒3:精确到毫秒6:精确到微秒- 省略时默认精度为 0
示例:
sql
created_at DATETIME(6)
可能保存:
text
2026-07-20 15:30:45.123456
8.4 获取当前日期和时间
| 写法 | 同义函数 | 作用 |
|---|---|---|
CURRENT_DATE / CURRENT_DATE() |
CURDATE() |
获取当前日期 |
CURRENT_TIME / CURRENT_TIME(fsp) |
CURTIME() |
获取当前时间 |
CURRENT_TIMESTAMP / CURRENT_TIMESTAMP(fsp) |
NOW() |
获取当前日期和时间 |
示例:
sql
SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT CURRENT_TIMESTAMP;
SELECT NOW();
8.5 日期类型选择
- 只保存生日、入职日期:
DATE - 保存完整业务时间:
DATETIME - 保存记录创建或修改时间:常用
TIMESTAMP或DATETIME - 保存时长、时间间隔:
TIME - 只保存年份:
YEAR
示例:
sql
CREATE TABLE employee (
id BIGINT UNSIGNED PRIMARY KEY,
name VARCHAR(50) NOT NULL,
birthday DATE,
work_start_time TIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
九、数据类型选择总原则
9.1 范围够用即可
在能够覆盖业务范围的前提下,优先选择占用空间较小的类型。
例如:
- 年龄不需要使用
BIGINT - 普通商品库存通常不需要使用
DECIMAL - 超大规模主键不宜使用
TINYINT
9.2 精确数据使用定点数
- 金额、税率、结算数据:
DECIMAL - 允许近似误差的计算:
FLOAT或DOUBLE
9.3 长度固定与否决定字符串类型
- 固定长度:
CHAR - 长度变化:
VARCHAR - 大段文字:
TEXT、MEDIUMTEXT、LONGTEXT
9.4 是否需要检索决定文本方案
- 经常按该字段查询、排序或建立索引:优先考虑
VARCHAR - 主要用于展示的大段内容:考虑
TEXT系列
9.5 日期不要随意用字符串保存
不推荐:
sql
birthday VARCHAR(20)
推荐:
sql
birthday DATE
使用专用日期类型可以获得:
- 合法性检查
- 日期计算
- 排序与比较
- 日期函数支持
十、综合建表示例
sql
CREATE TABLE user_profile (
id BIGINT UNSIGNED PRIMARY KEY,
student_no CHAR(12) NOT NULL,
username VARCHAR(50) NOT NULL,
gender ENUM('男', '女', '未知') DEFAULT '未知',
age TINYINT UNSIGNED,
balance DECIMAL(12, 2) DEFAULT 0.00,
email VARCHAR(100),
biography TEXT,
avatar_data BLOB,
birthday DATE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
字段分析:
| 字段 | 类型选择理由 |
|---|---|
id |
数据量可能较大,使用无符号 BIGINT |
student_no |
长度固定,使用 CHAR |
username |
长度可变,使用 VARCHAR |
gender |
候选值固定且只能选一个,使用 ENUM |
age |
非负且范围小,使用 TINYINT UNSIGNED |
balance |
金额要求精确,使用 DECIMAL |
biography |
内容可能较长,使用 TEXT |
avatar_data |
保存二进制数据,使用 BLOB |
birthday |
只需要日期,使用 DATE |
created_at |
保存完整日期和时间,使用 DATETIME |
十一、高频知识点
INT与INTEGER是同义类型。BOOL通常等价于TINYINT(1)。- 有符号整数可以保存负数,无符号整数从 0 开始。
FLOAT、DOUBLE可能存在精度误差。- 金额通常使用
DECIMAL。 CHAR是定长字符串,VARCHAR是变长字符串。CHAR更适合固定长度数据,VARCHAR更适合长度变化的数据。TEXT适合大段文字,BLOB适合二进制数据。ENUM只能选择一个值,SET可以选择多个值。DATE只保存日期,DATETIME保存日期和时间。TIME的取值范围可以超过一天,因此也可用于表示较长时长。fsp的范围为 0~6,用于控制小数秒精度。CURRENT_DATE获取当前日期。CURRENT_TIME获取当前时间。CURRENT_TIMESTAMP或NOW()获取当前日期和时间。
十二、易错点
易错点 1:把 VARCHAR(M) 的 M 当作字节数
VARCHAR(M) 中的 M 通常表示最大字符数,但实际存储空间还会受到字符集影响。
易错点 2:用 FLOAT 保存金额
浮点数可能产生精度误差,金额应优先使用 DECIMAL。
易错点 3:固定长度字段一律使用 VARCHAR
长度固定的数据使用 CHAR 通常更直观,例如学号、邮编和固定格式编码。
易错点 4:大段正文使用过短的 VARCHAR
文章正文、长说明等内容应考虑 TEXT、MEDIUMTEXT 或 LONGTEXT。
易错点 5:日期保存成普通字符串
使用 DATE、DATETIME 等专用类型,才能方便地进行日期比较、排序和计算。
易错点 6:混淆 ENUM 与 SET
ENUM:单选SET:多选
十三、知识速记
text
整数:TINYINT < SMALLINT < MEDIUMINT < INT < BIGINT
近似小数:FLOAT、DOUBLE
精确小数:DECIMAL
固定字符串:CHAR
可变字符串:VARCHAR
大文本:TEXT / MEDIUMTEXT / LONGTEXT
固定二进制:BINARY
可变二进制:VARBINARY
大二进制:BLOB / MEDIUMBLOB / LONGBLOB
单选:ENUM
多选:SET
日期:DATE
日期时间:DATETIME
时间戳:TIMESTAMP
时间或时长:TIME
年份:YEAR
当前日期:CURRENT_DATE / CURDATE()
当前时间:CURRENT_TIME / CURTIME()
当前日期时间:CURRENT_TIMESTAMP / NOW()