必须显式声明decimal(m,d),m和d缺一不可;电商价格用decimal(10,2),跨境用decimal(15,4)或decimal(18,6);存储过程变量、参数、除法、where条件、round与format均需严格标度控制。

必须用 DECIMAL(M,D) 显式声明,全程避免任何隐式转 DOUBLE,否则精度保障就失效了。
建表时 DECIMAL(M,D) 缺一不可
MySQL 不允许只写 DECIMAL 或 DECIMAL(10),必须同时指定总位数 M 和小数位 D,否则报错 ERROR 1064。
-
DECIMAL(10,2)表示最多 10 位数字、小数点后固定 2 位(如99999999.99) -
D不能为负,且必须 ≤M;设成DECIMAL(5,3)却插入123.4567,会四舍五入为123.457,不是报错 - 电商常规价格用
DECIMAL(10,2),跨境/汇率场景建议DECIMAL(15,4)或DECIMAL(18,6) - 别盲目设大:例如
DECIMAL(65,30)占约 33 字节,而DECIMAL(10,2)仅需 5 字节
存储过程里变量和参数必须带标度
在 CREATE PROCEDURE 中,DECLARE 变量或 IN 参数若漏写 D,中间计算极易被 MySQL 自动转成 DOUBLE。
- ✅ 正确:
DECLARE total DECIMAL(15,2);、IN amount DECIMAL(12,4) - ❌ 错误:
DECLARE total DECIMAL;、IN amount DECIMAL(12)(缺标度) - 调用时传裸数字如
CALL calc(100, 0.08),0.08默认按DOUBLE解析;应写成100.0或显式CAST(0.08 AS DECIMAL(5,4)) - 除法尤其危险:
100 / 3直接返回DOUBLE;必须写成CAST(100 AS DECIMAL(10,2)) / CAST(3 AS DECIMAL(10,2))
WHERE 条件和聚合中避开表达式左值
WHERE amount * 0.9 > 100 看似自然,实则三重风险:类型隐式提升、索引失效、中间浮点误差。
- MySQL 某些版本会把
amount * 0.9临时转成DOUBLE再比较,引入误差 -
amount * 0.9是表达式,无法使用amount字段上的普通索引(除非 MySQL ≥ 8.0.13 且建了函数索引) - 正确写法是移运算到右侧:
WHERE amount > 100 / 0.9,左侧保持纯字段引用 -
SUM(price * quantity)是安全的;但SUM(price) * SUM(quantity)数学上不等价,属常见逻辑错误
ROUND 和 FORMAT 别混用
ROUND() 是计算环节必需的精度控制手段,FORMAT() 只适合最终展示——它返回字符串,不能再参与后续运算。
- 折扣计算必须用
ROUND(price * 0.8, 2);否则29.99 * 0.8 = 23.992存入DECIMAL(10,2)会被截断为23.99,而ROUND能确保四舍五入 -
AVG(price / 100)和AVG(price) / 100数值可能不同:前者每行都做除法(触发中间精度缩放),后者只除一次 - 补零显示(如
100.00)才用FORMAT(amount, 2),别在计算链中用
最易被忽略的一点:DECIMAL 的精度推导是自动的,但不透明。两个 DECIMAL(10,2) 相乘结果是 DECIMAL(20,4),如果目标列或变量定义窄于该结果,INSERT 或赋值时可能静默截断——得靠人工校验宽度匹配,MySQL 不会主动预警。











