MySQL 数据类型直接影响存储效率与查询性能。数值、字符串、日期及特殊类型的选型原则与避坑技巧。通过 TINYINT、DECIMAL、CHAR/VARCHAR 等实战测试,对比精度与空间占用,提供整数范围、金额精度、定长变长选择的具体建议,帮助开发者避免溢出、精度丢失及存储浪费问题,实现数据库设计的规范化与优化。
字节跳动1 浏览
前言
在 MySQL 数据库设计中,数据类型的选择直接影响存储效率、查询性能和数据准确性。选对类型能避免存储空间浪费、数据溢出、精度丢失等问题,而选错则可能导致系统隐患(如用 INT 存储手机号导致截断)。本文将全面拆解 MySQL 核心数据类型,结合实战案例讲解选型技巧,帮你从'能用'升级到'用好'。
MySQL 数据类型分类总览
MySQL 的数据类型丰富,按功能可分为五大类,覆盖数值、字符串、日期、特殊类型等场景:
分类
核心类型
适用场景
数值类型
BIT、TINYINT、INT、BIGINT、FLOAT、DECIMAL
存储数字(年龄、金额、计数等)
字符串类型
CHAR、VARCHAR、TEXT、BLOB
存储文本(姓名、地址、大文本、二进制数据)
日期时间类型
DATE、DATETIME、TIMESTAMP
存储时间(生日、创建时间、时间戳)
特殊字符串
ENUM(枚举)、SET(集合)
固定选项(性别、爱好、状态等)
二进制类型
BLOB
存储图片、文件等二进制数据
数值类型:精准匹配数字范围与精度
数值类型是最常用的类型,核心关注范围和精度,避免数据溢出或精度丢失。
整数类型(BIT/TINYINT/INT/BIGINT)
整数类型按占用字节和范围分为 5 类,支持 UNSIGNED(无符号)修饰(默认有符号):
类型
占用字节
有符号范围
无符号范围
适用场景
BIT(M)
1-8
1-64 位(默认 1 位)
同有符号
存储 0/1(性别)、位掩码
TINYINT
1
-128 ~ 127
0 ~ 255
年龄、状态值(0-255)
SMALLINT
2
-32768 ~ 32767
0 ~ 65535
小范围计数(如订单编号)
INT
4
-2147483648 ~ 2147483647
0 ~ 4294967295
普通计数(如用户 ID)
BIGINT
8
-9e18 ~ 9e18
0 ~ 1.8e19
大数值(如手机号、雪花 ID)
关键实战要点:
避免无符号类型(UNSIGNED):虽然无符号类型能扩大正数范围,但可能导致溢出时报错(如 TINYINT UNSIGNED 插入 -1 直接报错),且与有符号类型计算时容易出现逻辑问题。建议直接用更大的整数类型(如用 INT 替代 TINYINT UNSIGNED)。
-- 1. 创建有符号 TINYINT 表CREATE TABLE test_tinyint1(age TINYINT);
-- 2. 插入合法值INSERT INTO test_tinyint1 VALUES(127); -- 成功(最大值)INSERT INTO test_tinyint1 VALUES(-128); -- 成功(最小值)-- 3. 插入越界值(报错)INSERT INTO test_tinyint1 VALUES(128); -- 报错:Out of range value for column 'age' at row 1-- 4. 创建无符号 TINYINT 表CREATE TABLE test_tinyint2(age TINYINT UNSIGNED);
-- 5. 插入无符号合法值INSERT INTO test_tinyint2 VALUES(255); -- 成功(无符号最大值)-- 6. 插入负数(无符号越界报错)INSERT INTO test_tinyint2 VALUES(-1); -- 报错:Out of range value for column 'age' at row 1
BIT 类型测试
BIT 存储位数据,默认 1 位(仅支持 0/1),位数 M 需≤64,查询时按 ASCII 码显示(易踩坑)。实际测试中有时可能显示为 16 进制,大家可自行验证:
-- 1. 创建 BIT(1) 字段的表CREATE TABLE test_bit(gender BIT(1));
-- 2. 插入合法值(0/1)INSERT INTO test_bit VALUES(0); -- 成功INSERT INTO test_bit VALUES(1); -- 成功-- 3. 插入越界值(报错)INSERT INTO test_bit VALUES(2); -- 报错:Data truncation: Data too long for column 'gender' at row 1-- 4. 查询 BIT 字段(关键:直接查询显示 ASCII 字符,需转成数字)SELECT gender, bin(gender+0) FROM test_bit;
-- 1. INT 存储手机号(越界测试)CREATE TABLE test_int(phone INT);
INSERT INTO test_int VALUES(13800138000); -- 报错:Out of range value for column 'phone' at row 1(INT 最大值 2147483647 < 13800138000)-- 2. BIGINT 存储手机号(成功)CREATE TABLE test_bigint(phone BIGINT);
INSERT INTO test_bigint VALUES(13800138000); -- 成功SELECT*FROM test_bigint;
发现 DECIMAL 的精度更准确。因此如果我们希望某个数据表示高精度,选择 DECIMAL。
关键结论:FLOAT 是近似存储,存在精度丢失;DECIMAL 是精确存储,适合金额、税率等场景。
FLOAT 表示的精度大约是 7 位,DECIMAL 整数最大位置 M 为 65,支持小数最大位置 D 是 30,如果 D 被省略,默认位 0,如果 M 被省略,默认是 10。建议如果希望小数的精度高,推荐使用 DECIMAL。
DECIMAL 范围测试
CREATE TABLE test_decimal2(price DECIMAL(5,2));
-- 总长度 5,小数位 2 → 范围 -999.99~999.99INSERT INTO test_decimal2 VALUES(999.99); -- 成功INSERT INTO test_decimal2 VALUES(1000.00); -- 报错:Out of range value for column 'price' at row 1
-- UTF8 编码下,VARCHAR 最大字符数=65532/3≈21844(预留 1-3 字节存长度)CREATE TABLE test_varchar_limit1(name VARCHAR(21845)) CHARSET=utf8; -- 报错:Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535.CREATE TABLE test_varchar_limit2(name VARCHAR(21844)) CHARSET=utf8; -- 成功