本文基于 MySQL 主流版本整理,涵盖所有常用数据类型、使用场景、底层原理、代码实战、易错点、选型建议。
一、前言
数据类型是建表的核心,选错类型会造成:存储空间浪费、查询效率低下、数据越界、精度丢失 等问题。MySQL 数据类型主要分为五大类:数值类型、位类型、字符串类型、日期时间类型、枚举&集合类型。下面从分类、语法、实战、易错点逐一讲解。
二、数值类型
数值类型分为整型、浮点型、定点数 ,支持 UNSIGNED(无符号)修饰符,默认有符号。
2.1 整型(TINYINT / SMALLINT / MEDIUMINT / INT / BIGINT)
2.1.1 整型范围与字节对照表
| 数据类型 | 占用字节 | 有符号范围 | 无符号(UNSIGNED)范围 |
|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 |
| SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 |
| MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 |
| INT(整数) | 4 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
| BIGINT(大整数) | 8 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
2.1.2 核心语法 & 代码实战
语法格式:
sql
字段名 整型类型 [UNSIGNED]
示例1:默认有符号 TINYINT(数据越界演示)
sql
-- 创建表,num 为默认有符号 TINYINT
CREATE TABLE test_tinyint(
num TINYINT
);
-- 正常插入
INSERT INTO test_tinyint VALUES(100);
-- 越界插入(超过最大值127),直接报错
INSERT INTO test_tinyint VALUES(128);
报错说明 :ERROR 1264 (22003): Out of range value,表示数值超出当前类型定义范围。
示例2:无符号 UNSIGNED 整型
无符号整型不支持负数,最小值从 0 开始:
sql
CREATE TABLE test_tinyint_unsigned(
num TINYINT UNSIGNED
);
-- 插入负数,越界报错
INSERT INTO test_tinyint_unsigned VALUES(-1);
-- 插入最大值 255,正常执行
INSERT INTO test_tinyint_unsigned VALUES(255);
2.1.3 易错点 & 选型建议
- 不推荐滥用 UNSIGNED
若INT存不下数据,INT UNSIGNED大概率也存不下,直接升级为 BIGINT 是最优方案。 - 场景选型
- 状态、性别、少量编号:用
TINYINT - 普通自增主键、常规数字:用
INT - 超大自增ID、长数字:用
BIGINT
- 状态、性别、少量编号:用
2.2 BIT 位类型
2.2.1 语法规则
sql
BIT[(M)]
M:位数,取值 1 ~ 64 ,省略 M 则默认BIT(1)- 底层按二进制位存储,极度节省空间
- 显示规则 :MySQL 会按照 ASCII 码 解析二进制值,不会直接显示数字
2.2.2 代码实战
sql
-- 创建表:id 普通整型,a 占8位 BIT
CREATE TABLE test_bit(
id INT,
a BIT(8)
);
-- 插入数字 65(ASCII 65 = 大写字母 A)
INSERT INTO test_bit VALUES(1, 65);
-- 查询结果:a 列显示 A,而非 65
SELECT * FROM test_bit;
2.2.3 经典场景:布尔状态(0/1)
仅存储是/否、启用/禁用 等二值状态,优先使用 BIT(1),空间最优:
sql
CREATE TABLE test_status(
is_enable BIT(1) -- 0=禁用,1=启用
);
INSERT INTO test_status VALUES(0);
INSERT INTO test_status VALUES(1);
-- 插入 2,超出 1 位范围,报错
INSERT INTO test_status VALUES(2);
报错 :Data too long for column,位数溢出。
2.3 浮点型 FLOAT
2.3.1 语法规则
sql
FLOAT[(M,D)] [UNSIGNED]
- 占用 4 字节
M:数据总显示长度(整数位+小数位)D:小数位数- 特性:自动四舍五入,精度约7位有效数字,存在精度丢失
2.3.2 范围计算 & 实战
FLOAT(4,2):总长度4,小数2位 → 范围-99.99 ~ 99.99FLOAT(6,3):总长度6,小数3位 → 范围-999.999 ~ 999.999
代码示例:
sql
CREATE TABLE test_float(
id INT,
salary FLOAT(4,2)
);
-- 正常数据
INSERT INTO test_float VALUES(1, 99.99);
-- 小数位超出,自动四舍五入
INSERT INTO test_float VALUES(2, 99.991);
SELECT * FROM test_float;
查询结果:99.991 自动变为 99.99。
2.3.3 无符号 FLOAT
无符号浮点不允许负数,负数会触发警告并修正:
sql
CREATE TABLE test_float_unsigned(
salary FLOAT(4,2) UNSIGNED
);
-- 插入负数,触发范围警告
INSERT INTO test_float_unsigned VALUES(-0.1);
2.4 定点数 DECIMAL(高精度小数)
2.4.1 语法规则
sql
DECIMAL[(M,D)] [UNSIGNED]
- 定点数,无精度丢失,金融、金额、账务场景首选
M:总位数(最大65),D:小数位数(最大30)- 省略
M默认10,省略D默认0
2.4.2 FLOAT 与 DECIMAL 精度对比(重点)
sql
CREATE TABLE test_decimal(
id INT,
num_float FLOAT(10,8),
num_decimal DECIMAL(10,8)
);
-- 插入同一串高精度小数
INSERT INTO test_decimal VALUES(1, 23.12345612, 23.12345612);
SELECT * FROM test_decimal;
执行结果:
FLOAT:23.12345695(精度错乱、丢失)DECIMAL:23.12345612(完全精准)
2.4.3 选型总结
- 普通小数、非精密计算:使用
FLOAT - 金额、货币、财务、科学计算 :强制使用
DECIMAL
三、字符串类型
字符串分为定长字符串 CHAR、可变长字符串 VARCHAR、大文本 TEXT、二进制 BLOB,是业务中使用频率最高的类型。
3.1 CHAR 定长字符串
3.1.1 语法 & 特性
sql
CHAR(L)
L:字符长度,最大 255 字符- 固定占用空间:无论实际存多少字符,都会占满定义长度
- 优点:查询、读写效率极高;缺点:浪费存储空间
3.1.2 代码实战
sql
-- 固定存储 2 个字符
CREATE TABLE test_char(
name CHAR(2)
);
-- 英文、中文都算作 1 个字符
INSERT INTO test_char VALUES('ab');
INSERT INTO test_char VALUES('中国');
-- 定义 CHAR(256) 直接报错,超出最大限制
CREATE TABLE test_char_err(name CHAR(256));
3.1.3 适用场景
数据长度固定的字段优先用 CHAR:
- 手机号、身份证号、银行卡号
- MD5 加密字符串、固定验证码
3.2 VARCHAR 可变长字符串
3.2.1 语法 & 底层规则
sql
VARCHAR(L)
- 可变长度:用多少空间占多少,节省存储
- 底层会额外占用 1~3字节 记录字符串长度,最大有效字节 65532
- 长度受字符集 限制(核心易错点):
utf8编码:1字符 = 3字节 → 最大字符数65532 / 3 = 21844gbk编码:1字符 = 2字节 → 最大字符数65532 / 2 = 32766
3.2.2 代码实战(字符集限制演示)
sql
-- utf8 编码,超过21844 直接报错
CREATE TABLE test_varchar_err(
name VARCHAR(21845)
) CHARSET=utf8;
-- 合法定义
CREATE TABLE test_varchar(
name VARCHAR(21844)
) CHARSET=utf8;
-- 中英文混合插入
INSERT INTO test_varchar VALUES('Hello MySQL');
INSERT INTO test_varchar VALUES('我爱编程,热爱技术');
3.2.3 CHAR 和 VARCHAR 对比表
| 类型 | 存储特点 | 空间利用率 | 查询效率 | 适用场景 |
|---|---|---|---|---|
| CHAR | 定长,不足补空格 | 低 | 高 | 固定长度数据 |
| VARCHAR | 变长,按需分配 | 高 | 略低 | 长度不固定数据 |
3.2.4 适用场景
数据长度不固定:用户名、昵称、地址、简介、备注等。
3.3 TEXT & BLOB 大文本/二进制
- TEXT :纯大文本,用于超长内容(文章正文、详情、大段备注)
- 不支持默认值、部分索引规则和普通字符串不同
- BLOB :二进制数据,用于存储图片、文件、音频 等二进制流 开发规范:不建议数据库直接存图片/文件,优先存文件路径。
四、日期时间类型
MySQL 常用三大时间类型:DATE、DATETIME、TIMESTAMP,业务时间字段必学。
4.1 类型对比
| 类型 | 格式 | 占用字节 | 时间范围 | 特性 |
|---|---|---|---|---|
| DATE | yyyy-MM-dd(仅日期) |
3 | 1000-01-01 ~ 9999-12-31 | 只存年月日 |
| DATETIME | yyyy-MM-dd HH:mm:ss(日期+时间) |
8 | 1000-01-01 ~ 9999-12-31 23:59:59 | 全时间,不受时区严格限制 |
| TIMESTAMP | yyyy-MM-dd HH:mm:ss(时间戳) |
4 | 1970-01-01 ~ 2038-01-19 | 自动更新、受时区影响 |
4.2 代码实战(核心特性:TIMESTAMP 自动刷新)
sql
CREATE TABLE test_time(
t_date DATE,
t_datetime DATETIME,
t_timestamp TIMESTAMP
);
-- 插入数据,timestamp 自动填充当前系统时间
INSERT INTO test_time(t_date, t_datetime)
VALUES('2026-06-12', '2026-06-12 10:20:30');
-- 更新任意字段,timestamp 会自动刷新为最新时间
UPDATE test_time SET t_date = '2026-01-01';
SELECT * FROM test_time;
4.3 选型建议 & 易错点
- 2038 时间坑 :
TIMESTAMP最大到 2038 年,长期项目优先用 DATETIME - 只需要年月日:用
DATE - 需要精确到时分秒、长期使用:用
DATETIME - 需记录数据最后修改时间 :可用
TIMESTAMP自动更新特性
五、枚举 ENUM & 集合 SET
专门用于固定选项的字段,ENUM 单选、SET 多选,底层以数字存储,效率高。
5.1 ENUM 枚举(单选)
5.1.1 语法
sql
ENUM('选项1','选项2','选项3'...)
- 单选类型,一个字段只能选其中一个值
- 底层存储数字编号:选项依次对应
1、2、3... - 最大支持 65535 个选项
5.1.2 实战:性别单选
sql
CREATE TABLE test_enum(
username VARCHAR(20),
gender ENUM('男','女','未知')
);
-- 直接写入字符串(推荐,可读性强)
INSERT INTO test_enum VALUES('张三','男');
-- 也可以写数字编号(不推荐),1=男,2=女
INSERT INTO test_enum VALUES('李四',2);
-- 按数字查询
SELECT * FROM test_enum WHERE gender = 2;
5.2 SET 集合(多选)
5.2.1 语法
sql
SET('选项1','选项2','选项3'...)
- 多选类型,一个字段可同时选中多个选项,逗号分隔
- 底层按二进制位 存储:选项依次对应
1、2、4、8、16... - 最大支持 64 个选项
5.2.2 实战:爱好多选
sql
CREATE TABLE test_set(
username VARCHAR(20),
hobby SET('篮球','足球','游泳','跑步')
);
-- 插入多个爱好,逗号分隔
INSERT INTO test_set VALUES('王五','篮球,游泳');
INSERT INTO test_set VALUES('赵六','足球,跑步,篮球');
5.3 SET 专属查询函数 FIND_IN_SET(高频考点)
普通 WHERE 字段='值' 无法查询包含该选项的多条数据 ,必须使用 FIND_IN_SET(查询值, 字段)。
错误写法
sql
-- 只能精准匹配"只有篮球"的数据,查不到同时选篮球+游泳的人
SELECT * FROM test_set WHERE hobby = '篮球';
正确写法(通用查询)
sql
-- 查询所有爱好包含"篮球"的用户(包含多选数据)
SELECT * FROM test_set WHERE FIND_IN_SET('篮球', hobby);
5.4 选型建议
- 固定单选(性别、学历、状态):用
ENUM - 固定多选(爱好、标签、权限):用
SET - 选项后期会频繁新增:不要用枚举/集合,改用字典表关联。
六、综合总结 & 开发规范
6.1 类型速选清单
- 整数
- 状态/少量数字:
TINYINT - 普通ID/编号:
INT - 超大ID/长整型:
BIGINT - 二值状态(0/1):
BIT(1)
- 状态/少量数字:
- 小数
- 普通小数:
FLOAT - 金额/财务/高精度:
DECIMAL
- 普通小数:
- 字符串
- 定长(手机号、身份证):
CHAR - 变长(姓名、地址):
VARCHAR - 超长文本(文章):
TEXT
- 定长(手机号、身份证):
- 时间
- 仅日期:
DATE - 完整时间、长期项目:
DATETIME - 自动更新修改时间(短期):
TIMESTAMP
- 仅日期:
- 固定选项
- 单选:
ENUM - 多选标签:
SET
- 单选:
6.2 高频易错点汇总
- 整型
UNSIGNED不能存负数,非必要不使用 VARCHAR最大长度受字符集限制,utf8 最大字符数 21844BIT类型按 ASCII 码显示,不直接展示数字FLOAT存在精度丢失,金额严禁使用TIMESTAMP存在 2038 年限,新项目优先DATETIMESET多选查询必须使用FIND_IN_SET函数
七、完整建表示例(综合运用)
sql
-- 综合所有数据类型建表演示
CREATE TABLE user_info(
id BIGINT PRIMARY KEY AUTO_INCREMENT, -- 大整数主键
phone CHAR(11), -- 定长手机号
username VARCHAR(30), -- 变长用户名
age TINYINT UNSIGNED, -- 年龄(无符号)
balance DECIMAL(10,2), -- 账户金额(高精度)
gender ENUM('男','女','保密'), -- 性别枚举
hobby SET('阅读','运动','游戏'), -- 爱好集合
register_date DATE, -- 注册日期
create_time DATETIME, -- 创建时间
is_valid BIT(1) -- 启用状态 0/1
);
通过本文的详细讲解和代码示例,相信你对MySQL数据类型已经有了全面而深入的理解。在实际建表时,请根据业务需求、存储效率和查询性能综合权衡,选择最合适的数据类型。如果觉得有用,欢迎点赞收藏,支持作者继续输出更多数据库干货!