Featured image of post 在数据库存储货币金额:该用 DECIMAL 还是 BIGINT?

在数据库存储货币金额:该用 DECIMAL 还是 BIGINT?

开发金流系统时,金额该用什么字段存?本文深入探讨为什么绝对不要用 FLOAT,以及如何选择 DECIMAL 或 BIGINT 来打造零误差、高性能的货币存储体系。

开发金流或电商系统,设计数据库存储金额字段时,你脑中是否曾闪过“金额就用 FLOATDOUBLE 存吧”的念头?

如果是的话,快停下你的手!你的系统可能正在偷偷漏钱。

为什么金融系统绝对不能用浮点数?一点点看似微不足道的精度误差,在庞大的交易量与时间累积下,可能会酿成无法挽回的灾难。

那我们到底该用什么来存钱呢?

为什么 FLOAT 是财务系统的毒药?

在电脑的世界里,数字是用二进制表示的。FLOAT(浮点数)在表示某些十进制小数时,其实是一种“近似值”。这就像是你试图用一把粗糙的电锯去切精致的蛋糕,不管你怎么小心,边缘总会掉下一些屑屑。

最经典的例子就是:0.1 + 0.2 在电脑里往往不等于 0.3。如果你处理的是几百万笔交易,这些“0.00000000000000004”的微小误差累积起来,账面就永远对不齐了。记住:

在金钱面前,任何“近似值”都是灾难。

会计师的精致账本:DECIMAL 的优势

如果你想要一个“看得到、对得到”的精确方案,DECIMAL 是数据库原生支持的定点数,也是业界最标准的做法。

DECIMAL 就像是会计师手中的精致账本,它会精确地把整数和小数分开存储,确保 0.1 + 0.2 绝对等于 0.3

业界黄金比例:DECIMAL(19, 4)

通常我们会建议使用 DECIMAL(19, 4)

  • 19:代表总共可以存 19 位数字(精度)。
  • 4:代表小数点后保留 4 位。

为什么要留 4 位小数?因为在计算利息、税率或汇率时,中间过程往往会产生超过 2 位的小数位,多留 2 位缓冲区可以增加运算的精确度,最后再依照业务需求四舍五入即可。

这样的容量,甚至足以让你买下好几个地球的 GDP 总和!

实际金融场景够不够用?

DECIMAL(19, 4) 为例:

  • 整数位:15 位
  • 最大金额:999,999,999,999,999
  • 美元换算:约 999 兆美元
参考值 金额
美国 GDP 约 27 兆美元
全球 GDP 总和 约 105 兆美元
全球财富总和 约 454 兆美元

DECIMAL(19, 4) 已经可以容纳远超全球财富总和的数字,对绝大多数金融系统来说完全足够。

各大数据库支持的最大 DECIMAL 的精度上限

数据库 最大 precision
MySQL / MariaDB 65
PostgreSQL 131072(整数位)+ 16383(小数位)
SQL Server 38
Oracle 38

游乐场的代币机器:BIGINT 最小单位法

如果你正在追求极致的性能,或是像 Stripe、支付宝这种具备超高并发需求的系统,那么 BIGINT(整数存储法) 可能是你的首选。

这种做法就像是游乐场的代币机:不管你投入多少钱,机器都会把它换算成“最小单位”来存储。例如:

  • 100.50 美元 → 存储为 10050(美分)
  • 100 台币 → 存储为 100(元)

为什么选 BIGINT?

原因 说明
速度极快 整数加减是 CPU 的拿手好戏,运算性能通常比 DECIMAL 快上许多。
空间效率 固定占用 8 bytes,非常适合超大型数据库。

不过,缺点是可读性较差,你打开数据库看到 10050 时,必须在脑袋(或代码)里自动除以 100。

终极对决:该怎么选?

要决定用哪一个,我们可以从 “查询频率”“系统规模” 来考量:

比较维度 DECIMAL BIGINT
可读性 极佳(直接看数字) 较差(需手动换算)
运算速度 普通 极快
适用场景 ERP、内部财务系统、一般电商 高频交易、超大型微服务、Stripe 风格 API

务实建议

适用场景 建议字段
一般电商、公司内部报表系统,且会计人员需要直接下 SQL 来查账 DECIMAL(19, 4)
高频交易系统、或需要极致扩展性 BIGINT

总结

简单来说,不管你选哪一种,千万、绝对、永久禁止使用 FLOAT 存钱! 选择正确的字段类型,才能让你的系统在金钱运算上稳如泰山。

All rights reserved,未經允許不得隨意轉載
Built with Hugo
主题 StackJimmy 设计