DECIMAL能避免浮点数精度误差,因其按十进制精确存储计算,而FLOAT/DOUBLE用二进制近似存储导致0.1+0.2≠0.3;需显式指定DECIMAL(M,D),否则默认DECIMAL(10,0)会截断小数。

DECIMAL 能避免 0.1 + 0.2 = 0.30000000000000004 这类误差
这不是显示问题,是底层存储逻辑不同:FLOAT/DOUBLE 把十进制小数转成二进制近似存储,而 0.1 在二进制里是无限循环小数,存进去就失真;DECIMAL 则按十进制逐位保存和计算,结果就是精确的 0.30。你在 MySQL 里执行 SELECT 0.1 + 0.2;,用 FLOAT 得到的是 0.30000000000000004,用 DECIMAL(10,2) 就是 0.30。
DECIMAL(M,D) 必须显式指定,否则默认 DECIMAL(10,0) 会丢掉小数
很多人建表时只写 DECIMAL,MySQL 会自动补成 DECIMAL(10,0)——小数位为 0。这意味着 INSERT INTO t(amount) VALUES(99.99); 实际存进去的是 99,两位小数直接被截断。电商常用 DECIMAL(10,2)(最大 99999999.99),高精度如汇率可选 DECIMAL(12,4) 或 DECIMAL(15,6)。M 最大 65、D 最大 30,但别盲目设大:DECIMAL(65,30) 占约 33 字节,DECIMAL(10,2) 只占 5 字节。
Float 的 (10,2) 只是显示格式,不约束精度;Decimal 的 (10,2) 是硬性校验
看这个对比:
CREATE TABLE t1 (f FLOAT(10,2), d DECIMAL(10,2)); INSERT INTO t1 VALUES (1234567.23, 1234567.23);
查出来 f 列可能是 1234567.25,因为 FLOAT 的 (10,2) 仅影响展示,不控制存储;而 d 列严格按十进制存,超范围直接报错 Out of range value for column 'd'。更危险的是,WHERE amount = 99.99 可能查不到刚插入的值,因为 FLOAT 存进去的其实是 99.98999786376953。
存储过程和函数调用中 DECIMAL 容易被隐式转成 DOUBLE
在存储过程中声明变量必须带精度,比如 DECLARE total_amount DECIMAL(15,2);,只写 DECIMAL 或 DECIMAL(15) 会报 ERROR 1064。调用时传裸数字如 CALL calc_tax(100, 0.08);,MySQL 默认把 0.08 当作 DOUBLE 解析,乘法中间结果可能变成浮点类型。稳妥做法是:CALL calc_tax(CAST(100 AS DECIMAL(10,2)), CAST(0.08 AS DECIMAL(5,4)));,或至少写成 100.0 和 0.080 显式提示定点常量。
上线后改 DECIMAL 精度要锁表重写,所以一开始就得想清楚 M 和 D;另外,DECIMAL 运算结果的类型有自动推导规则(比如两个 DECIMAL(10,2) 相乘得 DECIMAL(20,4)),如果目标变量声明太小,赋值时可能静默截断而非报错。


















