Decimal能避免浮点误差,因按十进制定点运算;Float/Double用二进制近似导致0.1+0.2≠0.3;DECIMAL(M,D)须显式指定,否则默认DECIMAL(10,0)会截断小数;电商常用DECIMAL(10,2),高精度场景可选DECIMAL(12,4)等;Float显示格式不约束精度,Decimal则硬性校验;Decimal性能略低但金融场景精度优先;上线后修改Decimal精度需锁表重写。
Float和Double用二进制近似存储十进制小数,0.1在二进制里是无限循环小数,存进去就失真。MySQL对FLOAT执行SELECT 0.1 + 0.2,结果常是0.30000000000000004;而DECIMAL(10,2)会严格按十进制算,结果就是0.30。
这不是显示问题,是底层存储和运算逻辑不同:Float走CPU浮点单元,Decimal由MySQL用定点算法逐位计算。
DECIMAL不设参数时默认为DECIMAL(10,0),小数位为0——这意味着INSERT INTO t(amount) VALUES(99.99)会被截断成99,钱直接丢掉两位。
DECIMAL(10,2)(最大99999999.99)DECIMAL(12,4)或DECIMAL(15,6)
DECIMAL(65,30)实际占用约33字节,远超DECIMAL(10,2)的5字节看这个实操对比:
CREATE TABLE t1 (f FLOAT(10,2), d DECIMAL(10,2));INSERT INTO t1 VALUES (1234567.23, 1234567.23);
查出来f列是1234567.25,d列才是1234567.23。原因:Float的FLOAT(10,2)只是显示格式,不约束存储精度;而Decimal的DECIMAL(10,2)是硬性约束,超长直接报错Out of range value for column 'd'。
更危险的是,Float在WHERE里用=匹配可能失败——WHERE amount = 99.99查不到刚插进去的99.99,因为存进去的其实是99.98999786376953。
Decimal比Float慢,主要因为:
但在真实交易系统中,单条金额字段的读写开销微乎其微。真正拖慢数据库的是索引设计、JOIN逻辑、没走索引的WHERE——而不是多花几纳秒算一个加法。拿精度换性能,在金融场景里是本末倒置。
真正容易被忽略的点是:Decimal的精度定义一旦上线就不能轻易改。比如从DECIMAL(10,2)扩到DECIMAL(12,2)要锁表重写数据,而Float改精度几乎无感。所以建表时就得想清楚业务未来3–5年的金额上限和精度需求。