MySQL中Decimal类型字段与字符串相加精度丢失原因及执行细节问询
问题背景
- 表名:
tb_assets - 字段名:
free - 字段类型:
decimal(32,16) - SQL-1:
update tb_assets set free = 16224.0221121221736466 where id=6; - 执行SQL-1后结果:
free: 16224.0221121221736466 - SQL-2:
update tb_assets set free = free + '100000000' where id=6; - 执行SQL-1和SQL-2后结果:
free: 100016224.0221121200000000 - 对比结果:
free: 16224.0221121221736466
free: 100016224.0221121200000000 - 现象总结:执行SQL-2后整数部分精度丢失(整数位数减1),小数部分精度丢失
正式问询
请解释为何Decimal类型字段与字符串相加会出现精度丢失,以及SQL-2的具体执行细节。
问题解答
一、SQL-2的具体执行细节
执行这条更新语句时,数据库会按以下步骤处理:
- 触发隐式类型转换:由于运算两边类型不一致(
decimal(32,16)和字符串),数据库必须先将二者转为同一类型才能进行加法运算。 - 字符串转数值的类型选择:对于纯整数字符串
'100000000',多数数据库不会直接匹配目标字段的decimal(32,16)精度,而是优先转为近似数值类型(如double),或默认精度的decimal(比如decimal(10,0))。 - 精度丢失的运算过程:
- 若转为double:原
free字段的decimal值会被强制转为double,但double仅能存储15-17位有效数字,原数值16224.0221121221736466有21位有效数字,转换时末尾精度直接丢失;随后与100000000的double值相加,结果仍是精度不足的近似值。 - 若转为低精度decimal:比如
decimal(10,0),与decimal(32,16)相加后,结果总精度可能超出数据库允许范围,触发自动精度调整,进而截断小数部分或调整整数位数。
- 若转为double:原
- 写回字段:将运算后的近似值或调整后的值转换回
decimal(32,16)时,已丢失的精度无法恢复,小数部分末尾会被填充为0,整数部分也会因转换规则出现位数缩减。
二、精度丢失的核心原因
- 隐式转换的类型不匹配:字符串转数值时未使用与目标字段一致的高精度decimal类型,而是转为近似数值类型或低精度decimal,导致精确的decimal值被迫降级,丢失有效数字。
- 近似数值类型的固有缺陷:double/float是基于二进制的近似存储格式,无法精确表示所有十进制小数,当decimal转成这类类型时,超过其有效数字范围的部分会被直接截断或舍入。
- 数据库运算的精度对齐规则:即使字符串转为decimal,若其默认精度与目标字段差异较大,运算结果的总精度可能超出数据库限制,触发自动精度调整,进而导致精度丢失。
内容的提问来源于stack exchange,提问作者Youga Tang
相关产品推荐
相关产品推荐

