MySQL 核心数据类型详解与实战案例
目录
1. 数据类型整体分类
2. 数值类型:精准存储数字
2.1 整数类型:tinyint 到 bigint
关键特性对比
实战案例:tinyint 越界测试
2.2 位类型:bit
2.3 小数类型:float、double 与 decimal
3. 字符串类型:存储文本与二进制
3.1 char:固定长度字符串
3.2 varchar:可变长度字符串
3.3 char 与 varchar 选择建议
4. 日期时间类型:记录时间信息
5. 特殊字符串类型:enum 与 set
5.1 enum:枚举(单选)
5.2 set:集合(多选)
6. 数据类型选择核心原则
在 MySQL 数据库设计中,选择合适的数据类型是保证性能与数据准确性的基础。不同数据类型在存储占用、取值范围和适用场景上差异显著,本文将从分类入手,结合实战案例拆解常用数据类型的用法与注意事项。
1. 数据类型整体分类
MySQL 数据类型可根据存储内容分为四大类,各类别下包含多个细分类型,具体如下表所示:
分类 | 包含数据类型 | 核心用途 |
---|---|---|
数值类型 | bit、tinyint、smallint、int、bigint、float、double、decimal | 存储整数、小数等数值 |
文本 / 二进制类型 | char、varchar、blob、text | 存储字符串、大文本或二进制数据 |
日期时间类型 | date、datetime、timestamp | 存储日期、时间或时间戳 |
特殊字符串类型 | enum、set | 存储枚举(单选)、集合(多选)数据 |
2. 数值类型:精准存储数字
数值类型是最常用的类型之一,需重点关注取值范围和精度,避免数据溢出或丢失。
2.1 整数类型:tinyint 到 bigint
整数类型按存储字节数从小到大分为四类,支持unsigned
(无符号)属性,默认为有符号(可存负数)。
关键特性对比
类型 | 占用字节 | 有符号范围 | 无符号范围 | 适用场景 |
---|---|---|---|---|
tinyint | 1 | -128 ~ 127 | 0 ~ 255 | 状态值(如 0 = 禁用、1 = 启用) |
smallint | 2 | -32768 ~ 32767 | 0 ~ 65535 | 小范围计数(如商品库存) |
int | 4 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 | 常规计数(如用户 ID) |
bigint | 8 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 | 超大范围计数(如订单号) |
实战案例:tinyint 越界测试
- 创建有符号 tinyint 表并插入数据
-- 创建数据库与表
create database test1_db;
use test1_db;
create table t1 (num tinyint);-- 插入合法数据(成功)
insert into t1 values(1), (-1), (127);-- 插入超界数据(失败):255超出有符号tinyint最大值127
insert into t1 values(255);
-- 报错:ERROR 1264 (22003): Out of range value for column 'num' at row 1
- 创建无符号 tinyint 表(
unsigned
)
create table t2 (num tinyint unsigned);-- 插入负数(失败):无符号类型不支持负数
insert into t2 values(-1);
-- 报错:ERROR 1264 (22003): Out of range value for column 'num' at row 1-- 插入255(成功):无符号tinyint最大值为255
insert into t2 values(255);
- 尽量不使用
unsigned
:若int
存不下数据,int unsigned
也大概率存不下,建议直接升级为bigint
。 - 整数类型后括号内的数字(如
int(11)
)是显示宽度,不影响实际存储范围,仅用于格式化显示。
2.2 位类型:bit
专门用于存储位数据,通过bit(m)
指定位数(m 范围 1-64,默认 1),适合存储开关状态(如在线 / 离线)。
-- 创建bit(1)表(默认1位,仅存0或1)
create table t3 (online bit);-- 插入0和1(成功)
insert into t3 values(0), (1);-- 插入2(失败):1位最多存1,2超出范围
insert into t3 values(2);
-- 报错:ERROR 1406 (22001): Data too long for column 'online' at row 1-- 注意:查询bit类型时,需按ASCII码解析(如bit(8)存65会显示'A')
create table t4 (online bit(8));
insert into t4 values(65); -- 65是'A'的ASCII码
select * from t4; -- 结果显示'A'
2.3 小数类型:float、double 与 decimal
用于存储带小数点的数字,核心差异在精度—— 前两者为浮点型(精度有损失),后者为定点型(精度无损失)。
关键对比与案例
类型 | 占用字节 | 精度特性 | 语法格式 | 适用场景 |
---|---|---|---|---|
float | 4 | 精度损失(约 7 位) | float(m,d) | 非精确计算(如温度) |
double | 8 | 精度损失(约 15 位) | double(m,d) | 较高精度非精确计算 |
decimal | 可变 | 精度无损失 | decimal(m,d) | 精确计算(如金额) |
案例 1:float 精度损失
-- 创建float(12,8)表(总位数12,小数位8)
create table t7 (salary float(12,8));-- 插入数据后精度丢失
insert into t7 values(5511.1456);
select * from t7; -- 结果:5511.14550781(原数据1456变为14550781)
案例 2:decimal 精度无损失
-- 创建decimal(14,8)表
create table t8 (salary decimal(14,8));-- 插入数据后精度保留
insert into t8 values(12345.65412);
select * from t8; -- 结果:12345.65412000(自动补0,无精度丢失)
m
:总位数(整数位 + 小数位),decimal
的 m 最大为 65。d
:小数位数,最大为 30,默认 0(即整数)。
3. 字符串类型:存储文本与二进制
字符串类型分为固定长度(char)和可变长度(varchar),另有存储大文本的 text 和二进制的 blob。
3.1 char:固定长度字符串
- 语法:
char(L)
,L 为字符数(不是字节数),最大 255。 - 特性:无论实际存储内容长度,均占用 L 个字符的空间,查询效率高。
- 适用场景:长度固定的数据(如身份证号、手机号)。
实战案例
-- 创建char(2)表(最多存2个字符,汉字也占1个字符)
create table t9 (name char(2));-- 插入1个字符(成功,自动补空格)
insert into t9 values('a');-- 插入2个汉字(成功)
insert into t9 values('中国');-- 插入3个字符(失败)
insert into t9 values('中国人');
-- 报错:ERROR 1406 (22001): Data too long for column 'name' at row 1
3.2 varchar:可变长度字符串
- 语法:
varchar(L)
,L 为字符数,最大受编码影响(utf8 下最大 21844,gbk 下 32766)。 - 特性:仅占用实际内容长度 + 1-3 字节(用于记录长度),节省空间,效率略低于 char。
- 适用场景:长度不固定的数据(如姓名、地址)。
实战案例
-- 创建varchar(6)表(最多存6个字符)
create table t10 (name varchar(6));-- 插入3个字符(成功)
insert into t10 values('abc');-- 插入6个字符(成功)
insert into t10 values('hello!');-- 插入7个字符(失败)
insert into t10 values('hello!!');
-- 报错:ERROR 1264 (22003): Out of range value for column 'name' at row 1
3.3 char 与 varchar 选择建议
- 长度固定选 char:如 MD5 值(32 位)、手机号(11 位)。
- 长度可变选 varchar:如姓名(2-4 个字符)、地址(10-50 个字符)。
- 优先平衡效率与空间:高频查询用 char,存储密集用 varchar。
4. 日期时间类型:记录时间信息
常用三种类型,需注意取值范围和自动更新特性,避免存储无效时间。
类型 | 格式 | 占用字节 | 取值范围 | 核心特性 |
---|---|---|---|---|
date | yyyy-mm-dd | 3 | 1000-01-01 ~ 9999-12-31 | 仅存日期 |
datetime | yyyy-mm-dd HH:ii:ss | 8 | 1000-01-01 ~ 9999-12-31 | 存日期 + 时间,无自动更新 |
timestamp | yyyy-mm-dd HH:ii:ss | 4 | 1970-01-01 ~ 2038-01-19 | 存日期 + 时间,自动更新 |
实战案例:timestamp 自动更新
-- 创建包含三种日期类型的表
create table t13 (t1 date, t2 datetime, t3 timestamp);-- 插入数据时,仅指定t1和t2,t3自动填充当前时间
insert into t13 (t1,t2) values('2001-01-01','2001-01-01 10:10:10');
select * from t13;
-- 结果:t3显示插入时的当前时间(如2024-09-09 21:51:21)-- 更新数据时,t3自动更新为当前时间
update t13 set t1='2002-02-02';
select * from t13;
-- 结果:t3显示更新时的当前时间(如2024-09-09 21:52:19)
注意事项
timestamp
受时区影响,且取值范围小(仅到 2038 年),长期存储建议用datetime
。- 插入日期时需符合
yyyy-mm-dd
格式,否则会报错或存储为0000-00-00
(无效日期)。
5. 特殊字符串类型:enum 与 set
用于存储预定义的选项,enum 为 “单选”,set 为 “多选”,底层用数字存储,效率高于字符串。
5.1 enum:枚举(单选)
- 语法:
enum('选项1','选项2',...)
,最多 65535 个选项。 - 特性:仅能选一个选项,底层存储选项对应的数字(1 = 选项 1,2 = 选项 2...)。
实战案例
-- 创建性别枚举表(男/女)
create table t14 (gender enum('男','女'));-- 插入合法选项(成功)
insert into t14 values('男');-- 插入数字1(成功,对应第一个选项“男”)
insert into t14 values(1);-- 插入未定义选项(失败)
insert into t14 values('未知');
-- 报错:ERROR 1265 (01000): Data truncated for column 'gender' at row 1
5.2 set:集合(多选)
- 语法:
set('选项1','选项2',...)
,最多 64 个选项。 - 特性:可多选,选项用逗号分隔,底层存储选项数字的和(1 = 选项 1,2 = 选项 2,4 = 选项 3...)。
实战案例
-- 创建爱好集合表(代码、羽毛球、乒乓球)
create table t14 (hobby set('代码','羽毛球','乒乓球'));-- 插入单个爱好(成功)
insert into t14 values('代码');-- 插入多个爱好(成功,用逗号分隔)
insert into t14 values('代码,羽毛球');-- 插入数字3(成功,3=1+2,对应“代码”和“羽毛球”)
insert into t14 values(3);-- 查询包含“羽毛球”的记录(用find_in_set函数)
select * from t14 where find_in_set('羽毛球',hobby);
注意事项
- 不建议用数字插入选项:不利于代码可读性,容易混淆。
- set 查询需用
find_in_set(sub, str)
函数:直接用hobby='羽毛球'
仅能查到只选 “羽毛球” 的记录,无法查到多选包含 “羽毛球” 的记录。
6. 数据类型选择核心原则
- 最小够用原则:如存储年龄用
tinyint
,不用int
,减少空间占用。 - 精度优先原则:金额、汇率等精确计算用
decimal
,不用float/double
。 - 场景匹配原则:时间戳用
datetime
(长期),状态开关用bit
,预定义选项用enum/set
。 - 避免无效值:如
unsigned
、timestamp
(2038 年问题),优先选择更兼容的类型。