跳到主要内容
跳到主要内容

时序存储效率

在前面学习了如何查询我们的 Wikipedia 统计数据集之后,接下来重点优化它在 ClickHouse 中的存储效率。 本节将演示一些实用技巧,在保持查询性能的同时减少存储需求。

类型优化

提升存储效率的一般方法是使用最合适的数据类型。 以 projectsubproject 列为例。这些列的数据类型为 String,但其不同取值的数量相对较少:

SELECT
    uniq(project),
    uniq(subproject)
FROM wikistat;
┌─uniq(project)─┬─uniq(subproject)─┐
│          1332 │              130 │
└───────────────┴──────────────────┘

这意味着我们可以使用 LowCardinality() 数据类型,它采用基于字典的编码方式。这样 ClickHouse 会存储内部的 ID 值,而不是原始的字符串值,从而节省大量空间:

ALTER TABLE wikistat
MODIFY COLUMN `project` LowCardinality(String),
MODIFY COLUMN `subproject` LowCardinality(String)

我们还为 hits 列使用了 UInt64 类型,它占用 8 字节,但其最大可表示的值相对较小:

SELECT max(hits)
FROM wikistat;
┌─max(hits)─┐
│    449017 │
└───────────┘

鉴于这个取值范围,我们可以改用 UInt32,它只占用 4 字节,最大可存储约 40 亿的数值:

ALTER TABLE wikistat
MODIFY COLUMN `hits` UInt32;

这将使该列在内存中的大小至少减少一半。请注意,由于压缩的原因,磁盘上的大小将保持不变。但要注意,不要选择过小的数据类型!

专用编解码器

在处理时间序列等序列型数据时,可以通过使用专用编解码器进一步提升存储效率。 总体思路是存储数值之间的差值,而不是数值本身的绝对值,这样在处理缓慢变化的数据时,可以显著减少所需的存储空间:

ALTER TABLE wikistat
MODIFY COLUMN `time` CODEC(Delta, ZSTD);

我们为 time 列使用了 Delta 编解码器,这非常适合时序数据。

合适的排序键也可以节省磁盘空间。 由于我们通常会按路径进行过滤,我们会将 path 添加到排序键中。 这需要重新创建表。

下面可以看到用于创建初始表和优化后表的 CREATE 命令:

CREATE TABLE wikistat
(
    `time` DateTime,
    `project` String,
    `subproject` String,
    `path` String,
    `hits` UInt64
)
ENGINE = MergeTree
ORDER BY (time);
CREATE TABLE optimized_wikistat
(
    `time` DateTime CODEC(Delta(4), ZSTD(1)),
    `project` LowCardinality(String),
    `subproject` LowCardinality(String),
    `path` String,
    `hits` UInt32
)
ENGINE = MergeTree
ORDER BY (path, time);

接下来我们来看一下每个表中的数据占用了多少空间:

SELECT
    table,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed,
    count() AS parts
FROM system.parts
WHERE table LIKE '%wikistat%'
GROUP BY ALL;
┌─table──────────────┬─uncompressed─┬─compressed─┬─parts─┐
│ wikistat           │ 35.28 GiB    │ 12.03 GiB  │     1 │
│ optimized_wikistat │ 30.31 GiB    │ 2.84 GiB   │     1 │
└────────────────────┴──────────────┴────────────┴───────┘

经过优化的表在压缩后占用的空间减少了 4 倍多一点。