数据库中的 LowCardinity
clickhouse 中有 LowCardinity 类型的列。
通过字典替代 string 类型的存储,节省空间。
LowCardinity(String)
native 中的 LowCardinity
在 clickhouse client 端,发送的时候使用 native 格式的 LowCardinity 进行发送,可以通过字典的格式发送。
测试。
创建一个表,字段只有一个值:
CREATE TABLE test
(
`traceID` String CODEC(ZSTD(1)),
`timestamp` DateTime('UTC') CODEC(ZSTD(1)),
)
ENGINE = MergeTree
PARTITION BY toDate(timestamp)
ORDER BY traceID
测试插入千万行,相同的 traceID 和相同的 timestamp。
traceID 长度 10个字节,而 datetime 长度只有四字节。
修改 traceid:
| Memory_usage(MB) | lowcardinity 列 | 非 lowcardinity 列 |
|---|---|---|
| lowcardinity 格式发送 | 150 | 400 |
| 非 lowcardinity 格式发送 | 300 | 400 |
| query_duration_s | lowcardinity 列 | 非 lowcardinity 列 |
|---|---|---|
| lowcardinity 格式发送 | 5 | 5 |
| 非 lowcardinity 格式发送 | 11 | 11 |
图中可以看出来,即使列不是 lowCardinity, 使用 lowCardinity 的格式发送,也能节省插入时间。(因为要发送的字节数大大减少了)。
虽然这没有节省 clickhouse server 的 memory_usages.
修改 timestamp:
| Memory_usage(MB) | 非 lowcardinity 列 |
|---|---|
| lowcardinity 格式发送 | 377 |
| 非 lowcardinity 格式发送 | 400 |
| query_duration_s | 非 lowcardinity 列 |
|---|---|
| lowcardinity 格式发送 | 11 |
| 非 lowcardinity 格式发送 | 11 |
当 timestamp 以 lowCardinity 格式插入,内存使用量会下降,这个很神奇。
插入时间没有下降,因为其实插入的字节数没有减少。
(因为 lowCardinity 的一个 bug, 长度跟插入的行数正相关,timestamp 只有四字节,比 traceID 少太多, 因此 lowCardinity 并没有减少插入的字节数)
当修复该 bug 后,见 github.com/zdyj3170101…
插入时间下降到 9s,memory_usage 依然不变, 为 377 MB。
疑惑的点
为什么使用 lowcardinity 格式发送 timestamp 会减少内存使用,但是发送 traceID 并不会?
TODO
1, 跟 traceID string 的长度无关, 减小成两个字节,不管插入是否使用 lowCardinity 都不会影响内存的使用。
2, 跟类型相关,将 traceID 从 str 改成 uint64,插入使用 lowCardinity 会减少 memory_usage_bytes.
对比 zstd 压缩。
使用 zstd 压缩同样能极高的减少网络字节数,从而提高插入速度,但是 clickhouse server 的内存使用量也提高了不少。
因此一般情况下还是没必要开启 zstd 压缩。
| Memory_usage(MB) | |
|---|---|
| Default | 400 |
| Zstd | 555 |
| query_duration_s | 非 lowcardinity 列 |
|---|---|
| Default | 11 |
| Zstd | 4 |
用途
对于 timestamp 类型的列,即使它在数据库中的类型不是 LowCardinity.
我们也可以在插入的时候,设置发送格式为 LowCardinity,这样可以节省插入时间。
以及插入的内存使用量(不一定?)