Khuyến nghị: DECIMAL (Exact numeric)
Luôn dùng DECIMAL cho tiền tệ, giá chính xác, đo lường. Tránh FLOAT/DOUBLE do lỗi floating-point binary.
Ví dụ minh họa
Tạo bảng với DECIMAL(10,2)
mysql> CREATE TABLE DemoTable (
Price DECIMAL(10,2)
);
mysql> INSERT INTO DemoTable VALUES(874674.50), (9948984.20), (12345678.99);
Kết quả
+-------------+ | Price | +-------------+ | 874674.50 | | 9948984.20 | | 12345678.99 | +-------------+
DECIMAL(M, D) giải thích
M(Precision): Tổng số chữ số tối đa (1-65). Ví dụ: 10D(Scale): Số chữ số sau dấu phẩy (0-30, D ≤ M). Ví dụ: 2DECIMAL(10,2): Tối đa 99999999.99 (8 số nguyên + 2 thập phân)- Lưu trữ: ~4 bytes per 9 digits (nén BCD)
So sánh các kiểu số
| Kiểu | Kích thước | Phạm vi | Độ chính xác | Dùng cho |
|---|---|---|---|---|
DECIMAL(10,2) | ~6 bytes | ±99,999,999.99 | Chính xác (Exact) | Tiền tệ, giá, đo lường |
DECIMAL(19,4) | ~9 bytes | ±999,999,999,999,999.9999 | Chính xác | Tài chính lớn, crypto |
FLOAT | 4 bytes | ~±3.4e38 | ~7 chữ số (Approx) | Khoa học, đồ họa, không cần chính xác |
DOUBLE | 8 bytes | ~±1.7e308 | ~15 chữ số (Approx) | Khoa học, tính toán phức tạp |
Tại sao KHÔNG dùng FLOAT/DOUBLE cho tiền?
mysql> CREATE TABLE test_float (f FLOAT, d DECIMAL(10,2)); mysql> INSERT INTO test_float VALUES(0.1, 0.1); mysql> SELECT f, d, f+0.2, d+0.2 FROM test_float; +-------+------+--------+-------+ | f | d | f+0.2 | d+0.2 | +-------+------+--------+-------+ | 0.1 | 0.10 | 0.30000000000000004 | 0.30 | +-------+-------+------+-------+
FLOAT: 0.1 + 0.2 = 0.30000000000000004 (lỗi binary floating point)
Best Practice cho tiền tệ
- DECIMAL(19,4) cho hệ thống tài chính (hỗ trợ tỷ giá, crypto)
- DECIMAL(12,2) cho e-commerce thông thường
- Lưu cent/đồng (integer) thay vì dollar:
price_cents INT(1000 = $10.00) - Luôn xử lý làm tròn ở application layer, không phụ thuộc DB
MySQL 8.0: CHECK CONSTRAINT
CREATE TABLE products (
price DECIMAL(10,2) CHECK (price >= 0)
);