開發金流或電商系統,設計資料庫儲存金額欄位時,你腦中是否曾閃過「金額就用 FLOAT 或 DOUBLE 存吧」的念頭?
如果是的話,快停下你的手!你的系統可能正在偷偷漏錢。
為什麼金融系統絕對不能用浮點數?一點點看似微不足道的精度誤差,在龐大的交易量與時間累積下,可能會釀成無法挽回的災難。
那我們到底該用什麼來存錢呢?
為什麼 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 存錢! 選擇正確的欄位類型,才能讓你的系統在金錢運算上穩如泰山。