DECIMAL 与 FLOAT/DOUBLE 的区别

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

  1. 金融和货币:金额、费率、利率、税率——必须精确
  2. 法律和审计相关:任何需要精确对账的场景
  3. 精度要求明确的场景:如 GPS 坐标保留 6 位小数

注意:在 Java 等语言中,从 MySQL 读取 DECIMAL 时建议用 BigDecimal 而不是 double,否则精度仍会在应用层丢失。

什么时候用 FLOAT/DOUBLE

  1. 科学计算:物理量、测量值,本身就有误差
  2. 统计数据:百分比、增长率、平均值(展示时四舍五入即可)
  3. 大数据聚合:对性能要求高且精度不是首要考虑
  4. 取值范围极大: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,甚至导致审计不过。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容