IEEE 754 雙精度 (DOUBLE) 與單精度 (FLOAT) 以二進制科學記號儲存,許多十進制小數(如 0.1、0.7)在二進制中為無限循環,導致近似值儲存。
CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
INSERT INTO t1 VALUES
(1, 101.40, 21.40), (1, -80.00, 0.00),
(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
(6, 0.00, 0.00), (6, -51.40, 0.00);
SELECT i, SUM(d1) AS a, SUM(d2) AS b
FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+ | i | a | b | +------+-------+------+ | 1 | 21.4 | 21.4 | | 2 | 76.8 | 76.8 | | 3 | 7.4 | 7.4 | | 4 | 15.4 | 15.4 | | 5 | 7.2 | 7.2 | | 6 | -51.4 | 0 | +------+-------+------+(真正不相等)。前 5 組
a、b顯示相同,但內部二進制表示不同,HAVING a <> b判定為真。第 6 組明顯不同。DECIMAL:精確儲存的解決方案
DECIMAL(M,D)以字串形式儲存每一位數字,精度固定、運算不失真。- 將
d1、d2改為DECIMAL(10,2)後,同樣查詢僅回傳第 6 行最佳實踐指南
| 場景 | 建議類型 | 理由 |
|---|---|---|
| 金額、價格、費率、匯率 | DECIMAL(19,4) 或 DECIMAL(10,2) | 精確到分/厘,避免會計差異 |
| 科學計算、座標、測量數值 | DOUBLE | 需要極大範圍、容許微小誤差 |
| 圖形渲染、機器學習特徵 | FLOAT | 節省空間、GPU 友善 |
| 整數計數、ID、狀態碼 | INT/BIGINT | 精確、效能最佳 |
-- ❌ 錯誤
WHERE price = 19.99
-- ✅ 正確:容差比較
WHERE ABS(price - 19.99) < 0.0001
-- ✅ 正確:DECIMAL 欄位直接比較
WHERE price = CAST(19.99 AS DECIMAL(10,2))
ROUND() 行為統一MySQL 8.0 採用「銀行家捨入」 (Round half to even),ROUND(1.5)=2、ROUND(2.5)=2,減少累積偏差;舊版本為四捨五入。遷移時需注意。