decimal是唯一能扛住复杂数学计算的类型,因float/double基于ieee 754二进制浮点,0.1+0.2≠0.3,误差在多轮运算中指数级放大;必须全程显式声明decimal(m,d)、cast中间值、锁死函数返回类型并手动控制round精度。

DECIMAL 是唯一能扛住复杂数学计算的类型,用 FLOAT 或 DOUBLE 做钱、比例、累加类运算,结果必然漂移。
为什么不能用 FLOAT/DOUBLE 做精确计算
MySQL 的 FLOAT 和 DOUBLE 是二进制浮点数,0.1 + 0.2 ≠ 0.3 —— 实际存的是 0.30000000000000004。这不是 bug,是 IEEE 754 标准的固有限制。存储过程里做多轮除法、累加、POW 后,误差会指数级放大。
声明和使用 DECIMAL 变量必须带精度
所有参与计算的变量、参数、临时表字段,只要涉及金额、税率、分摊、复利等,一律显式声明为 DECIMAL(M,D):
-
DECIMAL(15,2)适合普通订单金额(最大 9999999999999.99) -
DECIMAL(18,6)更稳妥,覆盖中间高精度计算(如利率、阶梯折扣系数) - 别写
DECIMAL不带括号,MySQL 会按默认(10,0)处理,小数直接被截断 - 函数参数也一样:
IN amount DECIMAL(18,6),不是IN amount DECIMAL
除法、ROUND、CAST 必须手动控制精度
MySQL 在混合类型表达式中会自动提升,但规则模糊且版本间不一致。最危险的是除法:
-
SELECT 100 / 3返回33.333333333333336(DOUBLE),不是你想的33.3333 - 正确写法:
CAST(100 AS DECIMAL(18,6)) / CAST(3 AS DECIMAL(18,6)) -
ROUND(val)默认取整,要保留小数必须写全:ROUND(val, 4) - 系统函数如
POW(1.05, n)返回DOUBLE,必须立刻CAST(POW(...) AS DECIMAL(18,6))
自定义函数返回值类型必须锁死
存储过程调用的自定义函数,若返回类型没声明或声明为 RETURNS DOUBLE,上游再怎么 CAST 也救不回精度:
- 函数定义必须写明:
RETURNS DECIMAL(18,6) - 函数体内所有中间变量也要用
DECIMAL,不能因“只是临时算一下”就用INT或省略精度 - 常见现象:单条测试没问题,批量跑第 1000 行开始结果偏移——八成是函数某处漏了
CAST或返回类型没锁死
ROUND 参数到 CAST 位置,缺一不可。靠 MySQL 自动推导,等于把数值命运交给随机数生成器。











