数值类型分为整数、浮点数和定点数三类。
整数——Int
在普遍的观念中,常用 Tinyint
、 Smallint
、 Int
和 Bigint
指代整数的不同取值范围。而 ClickHouse
则直接使用 Int8
、 Int32
和 Int64
指代 4
种大小的 Int
类型,其末尾的数字正好表明了占用字节的大小(8位=1字节),具体信息如下所示:
名称 | 大小(字节) | 范围 | 普遍观念 |
Int8 |
1 |
[-128, 127] |
Tinyint |
Int16 |
2 |
[-32768, 32767] |
Smallint |
Int32 |
4 |
[-2147483648, 2147483647] |
Int |
Int64 |
8 |
[-9223372036854775808, 9223372036854775807] |
Bigint |
ClickHouse
支持无符号的整数,使用前缀U
表示,具体信息如下所示:
名称 | 大小(字节) | 范围 | 普遍观念 |
UInt8 |
1 |
[0, 255] |
Tinyint Unsigned |
UInt16 |
2 |
[0, 65535] |
Smallint Unsigned |
UInt32 |
4 |
[0, 4294967295] |
Int Unsigned |
UInt64 |
8 |
[0, 18446744073709551615] |
Bigint Unsigned |
浮点数——Float
与整数类似, ClickHouse
直接使用 Float32
和 Float64
代表单精度浮点数以及双精度浮点数,具体信息如下所示:
名称 | 大小(字节) | 有效精度(位数) | 普遍观念 |
Float32 |
4 |
7 |
Float |
Float64 |
8 |
16 |
Double |
在使用浮点数的时候,应当要意识到他是有限精度的。假如,分别对 Float32
和 Float64
写入超过有效精度的数值,就会出现数据误差,例如将拥有 20
位小数的数值分别写入 Float32
和 Float64
时,就会出现数据误差。
$ SELECT toFloat32('0.12345678901234567890') as a, toTypeName(a) ┌──────────a─┬─toTypeName(toFloat32('0.12345678901234567890'))─┐ │ 0.12345679 │ Float32 │ └────────────┴─────────────────────────────────────────────────┘ $ SELECT toFloat64('0.12345678901234567890') as a, toTypeName(a) ┌───────────────────a─┬─toTypeName(toFloat64('0.12345678901234567890'))─┐ │ 0.12345678901234568 │ Float64 │ └─────────────────────┴─────────────────────────────────────────────────┘点击复制复制失败已复制
可以发现, Float32
从小数点后第 8
位起以及 Float64
从小数点后第 17
位起,都产生了数据溢出。
正无穷、负无穷以及非数字
ClickHouse
的浮点数支持正无穷、负无穷以及非数字的表达方式。
-- 正无穷: $ SELECT 0.8 / 0 ┌─divide(0.8, 0)─┐ │ inf │ └────────────────┘ -- 负无穷: $ SELECT -0.8 / 0 ┌─divide(-0.8, 0)─┐ │ -inf │ └─────────────────┘ -- 非数字: $ SELECT 0 / 0 ┌─divide(0, 0)─┐ │ nan │ └──────────────┘点击复制复制失败已复制
定点数——Decimal
如果要求更高精度的数值运算,则需要使用定点数。 ClickHouse
提供了 Decimal32
、 Decimal64
和 Decimal128
三种精度的定点数。可以通过两种形式声明定点:简写方式有 Decimal32(S)
、 Decimal64(S)
、 Decimal128(S)
三种,原生方式为 Decimal(P, S)
,其中:
P
代表精度,决定总数(整数部分+小数部分),取值范围是1~38
S
代表规模,决定小数位数,取值范围是0~P
简写方式与原生方式的对应关系如下所示:
名称 | 等效声明 | 范围 |
Decimal32(S) |
Decimal(1~9, S) |
[-10^{9-S}, 10^{9-S}][−109−S,109−S] |
Decimal64(S) |
Decimal(10~18, S) |
[-10^{18-S}, 10^{18-S}][−1018−S,1018−S] |
Decimal128(S) |
Decimal(19~38, S) |
[-10^{38-S}, 10^{38-S}][−1038−S,1038−S] |
在使用两个不同精度的定点数进行四则运算的时候,他们的小数点位数 S
会发生变化。在进行加法运算时, S
取最大值。
$ SELECT toDecimal64(2, 4) + toDecimal32(2, 2) ┌─plus(toDecimal64(2, 4), toDecimal32(2, 2))─┐ │ 4.0000 │ └────────────────────────────────────────────┘点击复制复制失败已复制
提示
toDecimal64(2, 4)
与 toDecimal32(2, 2)
相加后 S=4
。
在进行减法运算时,其规则与加法相同, S
同样会取最大值。
$ SELECT toDecimal32(4, 4) - toDecimal64(2, 2) ┌─minus(toDecimal32(4, 4), toDecimal64(2, 2))─┐ │ 2.0000 │ └─────────────────────────────────────────────┘点击复制复制失败已复制
在进行乘法运算时, S
取两者之和。
$ SELECT toDecimal64(2, 4) * toDecimal32(2, 2) ┌─multiply(toDecimal64(2, 4), toDecimal32(2, 2))─┐ │ 4.000000 │ └────────────────────────────────────────────────┘点击复制复制失败已复制
提示
toDecimal64(2, 4)
与 toDecimal32(2, 2)
相乘后 S=4+2=6
在进行除法运算时, S
取被除数的值,此时要求被除数S必须大于除数S,否则会报错。
$ SELECT toDecimal64(2, 4) / toDecimal32(2, 2) ┌─divide(toDecimal64(2, 4), toDecimal32(2, 2))─┐ │ 1.0000 │ └──────────────────────────────────────────────┘点击复制复制失败已复制
提示
toDecimal64(2, 4)
与 toDecimal32(2, 2)
相除后 S=4
定点数四则运算后,精度变化规则:
名称 | 规则 |
加法 | S=max(S1, S2) |
减法 | S=max(S1, S2) |
乘法 | S=S1+S2 |
除法 | S=S1 ( S1 为被除数, S1/S2 )(S1范围>=S2范围) |
在使用定点数时还有一点值得注意:由于现代计算器只支持 32
位和 64
位 CPU
,所以 Decimal128
是在软件层面模拟实现的,它的速度会明显慢与 Decimal32
和 Decimal64
。