MySQL执行UPDATE金额减法后出现异常极小值的原因及修复方案
问题产生原因
该异常是浮点数精度丢失导致的。
你当前account表的money字段使用了FLOAT/DOUBLE这类二进制浮点类型,这类类型的存储逻辑决定了它无法精确表示绝大多数十进制小数——和十进制无法精确表示1/3的原理一致,你看到的字段值7.54,实际存储的是一个无限接近7.54的近似值,并非精确等于7.54。执行减法运算时,这个存储的近似值和SQL语句里写的精确值7.54做运算,就会出现极小的误差,最终得到-0.000000038147这类非预期结果。
修复方案
- 根本解决:存储金额、财务数值这类要求精确计算的字段,禁止使用
FLOAT、DOUBLE浮点类型,改用DECIMAL定点数类型。比如通用的金额字段可以定义为DECIMAL(18,2),代表总长度18位、小数点后保留2位,该类型以精确值形式存储,算术运算不会出现精度丢失问题。 - 存量数据处理:如果表中已经有大量历史数据,修改字段类型前先对存量异常值做清洗修正,确认数值精度符合业务要求后再执行字段类型变更。
- 临时应急:如果暂时无法修改字段结构,可以在运算时用
ROUND()函数做精度截断,比如本次更新语句可以改写为:
该方案仅能临时规避异常显示问题,无法从根源解决精度误差,不建议长期使用。UPDATE account SET money = ROUND(money - 7.54, 2) WHERE id = 48;
注意:所有涉及交易、记账的金额类场景,必须使用DECIMAL类型存储;浮点类型仅适合存储对精度要求不高的数值,比如流量统计近似值、传感器粗略采集值等。
内容的提问来源于stack exchange,提问作者Cartosz
相关产品推荐
相关产品推荐

