The number types in pg are as follows:
name | storage size | describe | scope |
---|---|---|---|
smallint |
2 bytes | small range integer | -32768 to +32767 |
integer |
4 bytes | Typical choices for integers | -2147483648 to +2147483647 |
bigint |
8 bytes | wide range integer | -9223372036854775808 to +9223372036854775807 |
decimal |
variable | user-specified precision, exact | Up to 131072 digits before the decimal point and 16383 digits after the decimal point |
numeric |
variable | user-specified precision, exact | Up to 131072 digits before the decimal point and 16383 digits after the decimal point |
real |
4 bytes | variable precision, imprecise | 6 decimal places of precision |
double precision |
8 bytes | variable precision, imprecise | 15 decimal places of precision |
smallserial |
2 bytes | auto-incrementing small integer | 1 to 32767 |
serial |
4 bytes | auto-incrementing integer | 1 to 2147483647 |
bigserial |
8 bytes | auto-incrementing large integer | 1 to 9223372036854775807 |
If you need to process data with extremely high precision, or store data with precise precision, then use the numeric type, which has no range restrictions and precise storage, at the cost of storage size and processing speed, arithmetic operations on the type are faster than integer types numeric
or Floating point types are much slower.
For fixed-length numeric types, the smaller the type, the smaller the space occupied by the data on disk and in memory, and at the same time, the smaller the type, the narrower the range of values that can be stored. Whereas for integer types, a smaller type means a smaller range.
For floating-point types, a smaller type means less precision.
"Magic" rounding:
test=# SELECT 3.0::float8 * (1.0/5.0);
?column?
--------------------
0.6000000000000001
(1 row)
test=# SELECT 3.0::float8 * (1.0/5.0) <= 0.6;
?column?
----------
f
(1 row)
Small deviations in calculations and proper rounding are not acceptable when the system deals with currencies. Precise mathematics yields precise results.
test=# SELECT 3.0::numeric * (1.0/5.0);
?column?
-------------------------
0.600000000000000000000
(1 row)
Therefore, the official document also indicates that the numeric type is used when performing calculations with high precision requirements.
This is because the rounding behavior of the numeric type is "far away from zero", while the rounding behavior of double precision and float is "closer to the nearest even value".
test=# SELECT x,
test-# round(x::numeric) AS num_round,
test-# round(x::double precision) AS dbl_round
test-# FROM generate_series(-3.5, 3.5, 1) as x;
x | num_round | dbl_round
------+-----------+-----------
-3.5 | -4 | -4
-2.5 | -3 | -2
-1.5 | -2 | -2
-0.5 | -1 | -0
0.5 | 1 | 0
1.5 | 2 | 2
2.5 | 3 | 2
3.5 | 4 | 4
(8 rows)