数值数据类型
本教程共 46 篇 · 第 7 篇 · 更新于 2026-07-30 · 约 13 分钟阅读
7. 数值数据类型
本节目标:搞懂 MySQL 存数字的各种类型,整数怎么选、定点数和浮点数有什么区别、UNSIGNED 怎么用、BIT 干嘛的,学会按业务场景挑对类型,避免存错和浪费空间。
建表时每列都要指定类型。数值是最常用的一类,从用户 ID、年龄到金额、评分都靠它。这一节把数值类型一次讲透。
7.1 数值类型分两大类
MySQL 的数值类型分成两大阵营:
- 精确数值:整数和定点数,存什么就是什么,不丢精度;
- 近似数值:浮点数,存的是近似值,有微小误差。
涉及钱、计数、ID 这类必须精确的,用精确数值。科学计算、统计估算这类允许微小误差的,才考虑浮点数。
7.2 整数类型:五个档位
MySQL 的整数类型按”能存多大”分了五个档,加上标准 SQL 的 INTEGER。存储空间和取值范围对比如下:
| 类型 | 存储(字节) | 有符号范围 | 无符号范围(UNSIGNED) |
|---|---|---|---|
TINYINT | 1 | -128 ~ 127 | 0 ~ 255 |
SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 |
MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 |
INT | 4 | -21亿 ~ 21亿 | 0 ~ 42亿 |
BIGINT | 8 | 约 -922亿亿 ~ 922亿亿 | 0 ~ 1844亿亿 |
Note
INT和INTEGER是同义词,写哪个都行。MEDIUMINT是 MySQL 扩展,标准 SQL 没有。
怎么选整数类型
选型原则就一句话:够用就行,别贪大。类型越大,占空间越多,索引也越大,查询越慢。
- 状态、性别、是否删除这类小范围标志:
TINYINT; - 年龄、小计数:
TINYINT或SMALLINT; - 用户 ID、订单 ID:
INT或BIGINT。中小项目INT(42 亿)够用,海量数据用BIGINT; - 千万别所有 ID 都用
BIGINT,浪费空间。
7.3 UNSIGNED:只存非负数
加 UNSIGNED 关键字,把负数那部分空间让给正数,上限翻倍:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
age TINYINT UNSIGNED
);
id用INT UNSIGNED:范围 0~42 亿,全是正数,适合自增主键;age用TINYINT UNSIGNED:范围 0~255,存年龄绰绰有余。
Tip
- 自增主键、计数器这类不可能为负的字段,加
UNSIGNED是好习惯,能多用一倍空间。
7.4 显示宽度已被弃用
老教程里常看到 INT(11) 这种写法,括号里的 11 叫显示宽度。
注意:显示宽度不限制能存多大的数,INT(11) 和 INT 存储范围完全一样,那个 11 只是告诉某些客户端”显示时补足几位”。
从 MySQL 8.0.17 起,显示宽度被弃用(deprecated),写 INT(11) 会被警告。26.7 里直接写 INT 就行:
-- 旧写法,已弃用
age INT(11)
-- 正确写法
age INT
Warning
ZEROFILL(前导零填充)属性也一并被弃用了。要补零就用LPAD()函数在查询时处理,别再用ZEROFILL。
7.5 定点数 DECIMAL:钱必须用它
DECIMAL(定点数) 用来存绝对精确的小数,比如金额。它用 DECIMAL(P, D) 的形式定义:
P:精度(precision),总位数,1~65;D:标度(scale),小数点后位数,0~30,且D <= P。
举例:
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
amount DECIMAL(10, 2) NOT NULL
);
DECIMAL(10, 2) 表示总共 10 位、小数点后 2 位。能存的最大值是 99999999.99,适合存金额到分。
INSERT INTO orders(amount) VALUES(99.50), (100), (0.1);
mysql> SELECT amount FROM orders;
+--------+
| amount |
+--------+
| 99.50 |
| 100.00 |
| 0.10 |
+--------+
注意 100 存进去会变成 100.00,自动补齐小数位。存进去是什么样,取出来就是什么样,不会丢精度。
Note
DECIMAL、NUMERIC、DEC是同义词。DECIMAL(P)等价于DECIMAL(P, 0),纯整数。DECIMAL不写参数默认DECIMAL(10, 0)。
为什么金额不能用浮点数
浮点数用二进制存小数,很多十进制小数没法精确表示,会有微小误差:
mysql> SELECT 0.1 + 0.2;
+--------------------+
| 0.1 + 0.2 |
+--------------------+
| 0.30000000000000004 |
+--------------------+
0.1 + 0.2 居然不等于 0.3!这就是浮点误差。金额要是这么算,账迟早对不上。所以凡是涉及钱的,一律用 DECIMAL。
Tip
- 金额推荐
DECIMAL(19, 4):能存到万分位,符合财务规范。日常用DECIMAL(10, 2)也够。
7.6 浮点数 FLOAT 和 DOUBLE
浮点数存的是近似值,适合科学计算、统计这种允许误差的场景。
| 类型 | 存储 | 精度 |
|---|---|---|
FLOAT | 4 字节 | 单精度,约 6~7 位有效数字 |
DOUBLE | 8 字节 | 双精度,约 15 位有效数字 |
CREATE TABLE sensors (
id INT AUTO_INCREMENT PRIMARY KEY,
temperature FLOAT,
pressure DOUBLE
);
浮点数也可以写 FLOAT(P, D),但和 DECIMAL 的 P, D 含义略有不同,实际很少这么用,一般直接写 FLOAT 或 DOUBLE。
Warning别用浮点数存钱!前面那个
0.1+0.2的例子就是教训。浮点数适合存温度、经纬度、传感器读数这类”本来就是近似值”的数据。
7.7 DECIMAL vs FLOAT vs DOUBLE 对比
| 对比项 | DECIMAL | FLOAT | DOUBLE |
|---|---|---|---|
| 是否精确 | 精确 | 近似 | 近似 |
| 存储 | 变长(按位数) | 4 字节 | 8 字节 |
| 计算速度 | 较慢(要解码) | 快 | 快 |
| 典型用途 | 金额、计数 | 科学计算 | 高精度科学计算 |
一句话总结:要精确就用 DECIMAL,要快且允许误差就用 FLOAT/DOUBLE。
7.8 BIT 类型:位字段
BIT(M) 用来存位字段,M 是位数,1~64。它本质是存一串二进制位,常用来存一组开关标志。
CREATE TABLE user_flags (
id INT PRIMARY KEY,
permissions BIT(8) -- 8 位,可表示 8 个开关
);
插入时用 b'...' 写二进制字面量:
INSERT INTO user_flags VALUES(1, b'10101010');
mysql> SELECT permissions + 0 FROM user_flags WHERE id = 1;
+------------------+
| permissions + 0 |
+------------------+
| 170 |
+------------------+
b'10101010' 转成十进制就是 170。直接 SELECT permissions 会显示成特殊字符,加 + 0 才能看到十进制值。
Note
BIT用得不多,新手了解即可。大多数场景用TINYINT存 0/1 标志更直观。
7.9 BOOLEAN 其实是 TINYINT
MySQL 没有真正的 BOOLEAN 类型。BOOL 和 BOOLEAN 是 TINYINT(1) 的别名:
CREATE TABLE users (
id INT PRIMARY KEY,
is_active BOOLEAN
);
存进去的是 0 或 1(TRUE 等于 1,FALSE 等于 0):
INSERT INTO users VALUES(1, TRUE), (2, FALSE);
mysql> SELECT id, is_active FROM users;
+----+-----------+
| id | is_active |
+----+-----------+
| 1 | 1 |
| 2 | 0 |
+----+-----------+
查的时候用 WHERE is_active = TRUE 或 WHERE is_active = 1 都行,效果一样。
7.10 数值溢出怎么处理
如果插入的值超过了类型范围,MySQL 的行为取决于 SQL 模式:
- 严格模式(默认):直接报错,拒绝插入;
- 非严格模式:截断到范围的边界值,给个警告。
-- age 是 TINYINT UNSIGNED(0~255)
INSERT INTO users(age) VALUES(300);
严格模式下报错:
ERROR 1264 (22003): Out of range value for column 'age' at row 1
Tip
- 8.0+ 默认就是严格模式,溢出会报错而不是悄悄截断,这能避免脏数据。生产环境一定要保持严格模式。
7.11 数值类型选型建议
把这一节的选型原则归纳成几条:
- 整数够用就行:小范围用
TINYINT,ID 用INT,海量数据 ID 用BIGINT; - 不可能为负就加
UNSIGNED:主键、计数都加上; - 金额一律
DECIMAL:DECIMAL(19, 4)或DECIMAL(10, 2),别用浮点数; - 科学计算用
FLOAT/DOUBLE:温度、坐标、传感器数据; - 布尔值用
BOOLEAN(实际是TINYINT); - 别写显示宽度:写
INT别写INT(11),8.0.17 起已弃用; - 能用整数别用字符串:用
INT存状态码,别用'1'、'2'这种字符串。
7.12 小结
这一节搞定了数值类型:
- 整数五档:
TINYINT<SMALLINT<MEDIUMINT<INT<BIGINT,按需选; UNSIGNED只存非负数,上限翻倍,主键常用;- 显示宽度
INT(11)已弃用,直接写INT; DECIMAL(P,D)存精确小数,金额必用;FLOAT/DOUBLE存近似值,科学计算用;BIT存位字段,BOOLEAN是TINYINT别名;- 溢出在严格模式下报错,保持严格模式防脏数据。
下一节讲字符串类型,这是建表时用得最多的另一大类。