数据模型
ClickHouse 采用经典的表格存储模型,属于结构化数据存储系统。我们分别从面向用户的逻辑数据模型和面向底层存储的物理数据模型进行介绍。
1. 逻辑数据模型
从用户使用角度看,ClickHouse 的逻辑数据模型与关系型数据库有一定的相似:一个集群包含多个数据库,一个数据库包含多张表,表用于实际存储数据。
与传统关系型数据库不同的是,ClickHouse 是分布式系统,如何创建分布式表呢?
ClickHouse 的设计是:先在每个 Shard 每个节点上创建本地表(即 Shard 的副本),本地表只在对应节点内可见;然后再创建分布式表,映射到前面创建的本地表。这样用户在访问分布式表时,ClickHouse 会自动根据集群架构信息,把请求转发给对应的本地表。
创建分布式表的具体样例如下:
CREATE TABLE IF NOT EXISTS user_cluster ON CLUSTER cluster_3shards_1replicas
(
id Int32,
name String
)ENGINE = Distributed(cluster_3shards_1replicas, default, user_local,id);
Distributed表引擎的定义形式如下所示:
Distributed(cluster_name, database_name, table_name[, sharding_key])
各个参数的含义分别如下:
cluster_name:集群名称,与集群配置中的自定义名称相对应。
database_name:数据库名称
table_name:表名称
sharding_key:可选的,用于分片的key值,在数据写入的过程中,分布式表会依据分片key的规则,将数据分布到各个节点的本地表。
创建分布式表是读时检查的机制,也就是说对创建分布式表和本地表的顺序并没有强制要求。
同样值得注意的是,在上面的语句中使用了ON CLUSTER分布式DDL,这意味着在集群的每个分片节点上,都会创建一张Distributed表,这样便可以从其中任意一端发起对所有分片的读、写请求。
创建完成上面的分布式表时,在每台机器上查看表,发现每台机器上都存在一张刚刚创建好的表。接下来就需要创建本地表了,在每台机器上分别创建一张本地表:
CREATE TABLE IF NOT EXISTS user_local
(
id Int32,
name String
)ENGINE = MergeTree()
ORDER BY id
PARTITION BY id
PRIMARY KEY id;
其中部分关键概念介绍如下,分区、数据块、排序等概念会在物理存储模型部分展开介绍:
MergeTree:ClickHouse 中使用非常多的表引擎,底层采用 LSM Tree 架构,写入生成的小文件会持续 Merge。
Distributed:ClickHouse 中的关系映射引擎,它把分布式表映射到指定集群、数据库下对应的本地表上。
更直观的,ClickHouse 中的逻辑数据模型如下:

接下来,我们来介绍每个分片副本内部的物理存储模型,具体如下:
数据分区:每个分片副本的内部,数据按照 PARTITION BY 列进行分区,分区以目录的方式管理,本文样例中表按照时间进行分区。
列式存储:每个数据分区内部,采用列式存储,每个列涉及两个文件,分别是存储数据的 .bin 文件和存储偏移等索引信息的 .mrk2 文件。
数据排序:每个数据分区内部,所有列的数据是按照 ORDER BY 列进行排序的。可以理解为:对于生成这个分区的原始记录行,先按 ORDER BY 列进行排序,然后再按列拆分存储。
数据分块:每个列的数据文件中,实际是分块存储的,方便数据压缩及查询裁剪,每个块中的记录数不超过 index_granularity,默认 8192。
主键索引:主键默认与 ORDER BY 列一致,或为 ORDER BY 列的前缀。由于整个分区内部是有序的,且切割为数据块存储,ClickHouse 抽取每个数据块第一行的主键,生成一份稀疏的排序索引,可在查询时结合过滤条件快速裁剪数据块。
原文链接:https://blog.csdn.net/shan19920501/article/details/125235310




