DECIMAL 与 FLOAT/DOUBLE 的区别
数据类型概述
MySQL 中用于存储小数的三种类型各有特点:
| 类型 | 存储方式 | 精度 | 占用空间 | 适合场景 |
|---|---|---|---|---|
| FLOAT | 浮点数(4 字节) | 约 7 位有效数字 | 4 字节 | 科学计算、精度要求不高的场景 |
| DOUBLE | 浮点数(8 字节) | 约 15 位有效数字 | 8 字节 | 科学计算、更大范围的值 |
| DECIMAL | 定点数(字符串存储) | 精确 | 变长(每 9 位 4 字节) | 金融、货币、精确计算 |
本质区别:浮点数 vs 定点数
以最简单的例子说明问题:
-- FLOAT 示例
CREATE TABLE t (price FLOAT(10,2));
INSERT INTO t VALUES (0.1);
SELECT price FROM t; -- 0.10(显示正常,但内部不精确)
SELECT price * 3 FROM t; -- 可能得到 0.30000000000000004
-- DECIMAL 示例
CREATE TABLE t2 (price DECIMAL(10,2));
INSERT INTO t2 VALUES (0.1);
SELECT price FROM t2; -- 0.10
SELECT price * 3 FROM t2; -- 0.30(精确)
FLOAT/DOUBLE 为什么不精确
FLOAT 和 DOUBLE 使用 IEEE 754 标准,以二进制表示小数。有些十进制小数(如 0.1)无法用有限的二进制精确表示,类似 1/3 无法用十进制精确表示一样。
0.1 在二进制中是无限循环小数:0.00011001100110011…
FLOAT 存储时截断到 24 位有效二进制位,DOUBLE 到 53 位,这导致:
– FLOAT 精度约 6-7 位十进制有效数字
– DOUBLE 精度约 15-16 位十进制有效数字
– 比较 0.1 + 0.2 = 0.3 在 FLOAT/DOUBLE 下可能为 FALSE
DECIMAL 为什么精确
DECIMAL 将数字以十进制格式按字面值存储(每 4 字节存 9 位数字),计算时 MySQL 会进行精确的十进制运算,不产生舍入误差。
存储空间对比
DECIMAL 的存储空间取决于精度:
DECIMAL(M,D) 的存储 = 整数部分位数 + 小数部分位数
每 9 位数字占 4 字节,剩余部分:
剩 1-2 位占 1 字节
剩 3-4 位占 2 字节
剩 5-6 位占 3 字节
剩 7-9 位占 4 字节
例如 DECIMAL(18,2):整数 16 位 + 小数 2 位 → 9+7 位 → 4+4=8 字节。而 DOUBLE 固定 8 字节,FLOAT 固定 4 字节。
性能差异
- 计算速度:FLOAT/DOUBLE 由 CPU 硬件浮点单元直接加速,比 DECIMAL 的软件模拟快 10-20 倍
- 存储空间:DECIMAL 需要更多空间(尤其是高精度时),影响缓冲池利用率和 IO
- 索引效率:DECIMAL 作为精确类型,范围查询和排序更可预测
实际选择指南
什么时候用 DECIMAL
- 金融和货币:金额、费率、利率、税率——必须精确
- 法律和审计相关:任何需要精确对账的场景
- 精度要求明确的场景:如 GPS 坐标保留 6 位小数
注意:在 Java 等语言中,从 MySQL 读取 DECIMAL 时建议用 BigDecimal 而不是 double,否则精度仍会在应用层丢失。
什么时候用 FLOAT/DOUBLE
- 科学计算:物理量、测量值,本身就有误差
- 统计数据:百分比、增长率、平均值(展示时四舍五入即可)
- 大数据聚合:对性能要求高且精度不是首要考虑
- 取值范围极大:DOUBLE 的范围远超 DECIMAL
一个折中方案
如果业务上需要精确的小数运算但数据量极大,可以考虑:
– 数据库存整数(如金额存”分”而不是”元”)
– 应用层做单位转换显示
这样既保证了精度,又避免了 DECIMAL 的运算性能开销。
面试常问题
Q:DECIMAL(10,2) 能存的最大值是多少?
A:整数部分 8 位,最大 99,999,999.99。
Q:为什么 FLOAT 和 DOUBLE 比较时要用范围而不是等值?
A:因为浮点数不精确,0.1 可能存为 0.10000000149011612,等值比较可能失败。应该用 ABS(a - b) < 0.00001。
Q:MySQL 中 DECIMAL 是变长存储吗?
A:是的。每 9 位数字用一个 4 字节的"块"存储,不足 9 位的部分按剩余位数使用 1-4 字节。所以 DECIMAL(10,2) 比 DECIMAL(18,2) 占的空间小。
Q:如果把金额存 DOUBLE,会出什么问题?
A:对账时可能差几分钱,累计下来可能差几千块。这是生产级别的 BUG,甚至导致审计不过。


暂无评论内容