Khắc phục vấn đề độ chính xác FLOAT trong MySQL dùng DECIMAL
Kiểu FLOAT và DOUBLE lưu số thực theo chuẩn IEEE 754 (binary floating-point), gây ra sai số làm tròn (ví dụ: 0.1 + 0.2 ≠ 0.3). Giải pháp: dùng DECIMAL(p,s) (fixed-point, exact precision).
Ví dụ minh họa
Tạo bảng với DECIMAL(10,2) (tổng 10 chữ số, 2 chữ số thập phân):
mysql> CREATE TABLE DemoTable (Amount DECIMAL(10,2)); Query OK, 0 rows affected (0.54 sec)
Chèn các số lớn có phần thập phân:
mysql> INSERT INTO DemoTable VALUES(2194848.90); Query OK, 1 row affected (0.65 sec) mysql> INSERT INTO DemoTable VALUES(90309393.79); Query OK, 1 row affected (0.25 sec) mysql> INSERT INTO DemoTable VALUES(8999999.68); Query OK, 1 row affected (0.30 sec) mysql> INSERT INTO DemoTable VALUES(90900000.99); Query OK, 1 row affected (0.26 sec)
Xem dữ liệu (lưu chính xác, không sai số):
mysql> SELECT * FROM DemoTable;
+-------------+ | Amount | +-------------+ | 2194848.90 | | 90309393.79 | | 8999999.68 | | 90900000.99 | +-------------+ 4 rows in set (0.00 sec)
So sánh FLOAT vs DECIMAL
| Đặc điểm | FLOAT / DOUBLE | DECIMAL(p,s) |
|---|---|---|
| Lưu trữ | Binary floating-point (IEEE 754) | Decimal fixed-point (chuỗi số) |
| Độ chính xác | Gần đúng (approximate) | Chính xác tuyệt đối (exact) |
| Phạm vi | Rất lớn (10±308) | Tùy p (max 65 chữ số) |
| Hiệu suất | Nhanh (hardware FPU) | Chậm hơn (software math) |
| Phù hợp | Khoa học, đồ họa, ML | Tài chính, tiền tệ, đo lường |
Ví dụ lỗi FLOAT kinh điển
CREATE TABLE test_float (val FLOAT); INSERT INTO test_float VALUES(0.1), (0.2), (0.3); SELECT * FROM test_float WHERE val = 0.3; -- Có thể trả về rỗng! SELECT val, val*100 FROM test_float; -- 0.1 → 10.000000000000001
Cú pháp DECIMAL
DECIMAL(precision, scale) -- precision: Tổng số chữ số (1-65) -- scale: Số chữ số sau dấu phẩy (0-precision)
Khuyến nghị
- Tiền tệ/VNĐ:
DECIMAL(15,0)(lưu VNĐ nguyên, không thập phân) - USD/EUR:
DECIMAL(10,2)hoặcDECIMAL(19,4)(cho phép tính toán trung gian chính xác) - Tỷ lệ/Phần trăm:
DECIMAL(5,4)(0.0000 - 9.9999) - Khoa học:
DOUBLE(hoặcFLOATcho tiết kiệm dung lượng) - Luôn dùng
DECIMALcho cộtWHERE col = 123.45hoặcGROUP BYđể tránh lỗi so sánh