大数据-138 - ClickHouse 集群 表引擎详解3 - MergeTree 存储结构 数据标记 分区 索引 标记 压缩协同

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: 大数据-138 - ClickHouse 集群 表引擎详解3 - MergeTree 存储结构 数据标记 分区 索引 标记 压缩协同

点一下关注吧!!!非常感谢!!持续更新!!!

目前已经更新到了:

Hadoop(已更完)

HDFS(已更完)

MapReduce(已更完)

Hive(已更完)

Flume(已更完)

Sqoop(已更完)

Zookeeper(已更完)

HBase(已更完)

Redis (已更完)

Kafka(已更完)

Spark(已更完)

Flink(已更完)

ClickHouse(正在更新···)

章节内容

上节我们完成了如下的内容:


MergeTree 存储结构

MergeTree 一级索引

MergeTree 跳数索引

MergeTree

续接上节部分

数据存储

ClickHouse 是一个 列式存储 数据库,这意味着每一列的数据是单独存储的,而不是像行式数据库那样将每一行作为一个整体来存储。列式存储的优势在于,它可以针对特定的查询只读取相关的列,大大减少了 I/O 操作,尤其在进行聚合或过滤操作时表现出色。每一列的数据通常会被划分成若干块(block),这些块被组织在存储引擎的元数据和数据文件中。ClickHouse 的存储引擎有多个,常用的包括 MergeTree 引擎及其变种。


表由按主键排序的数据 片段组成。

当数据被插入到表中时,会分成数据片段并按主键的字典序排序。


例如:主键是(CounterID, Date)时,片段中的数据按CounterID排序,具有相同的CounterID的部分按Date排序。

不同的分区的数据会被划分成不同的片段,ClickHouse在后台合并数据片段以便高效的存储,不会合并来自不同分区的数据片段,这个合并机制并不保证相同的主键的所有行都会合并到同一个数据片段中。


ClickHouse会为每个数据片段创建一个索引文件,索引文件包括每个索引行的主键值,索引行号定义为 n * index_granularity。最大的N等于总行数除以index_granularity的值的整数部分。对于每列,跟主键相同的索引行也会写入标记,这些标记可以让你直接找到数据所在的列。

你可以只用单一达标不断的一块块往里加入数据,MergeTree引擎就是为了这样的场景。


按列存储

在MergeTree中数据按列存储,具体到每个字段列,都拥有一个bin数据文件,最终存储数据的文件。

按列存储的好处:


更好的压缩

最小化数据扫描范围

MergeTree往bin里存数据的步骤:


对数据进行压缩

根据ORDER BY排序

数据以压缩块的形式写入bin文件

压缩数据块

CompressionMethod_CompressedSize_UnccompressedSize

一个压缩数据块由两部分组成:


头信息

压缩数据

头信息固定使用9位字节表示,1个UInt8(1字节) + 2个UInt32(4字节),分别表示压缩算法,压缩后的数据大小,压缩前的数据大小。

如:0x821200065536


0x82是压缩方法

12000是压缩后数据大小

65536是压缩前数据大小

可以使用如下的语句,来查看压缩的情况


# 这里路径可能不一样 根据你的来
cd /var/lib/clickhouse/data/default/mt_table/202407_1_1_0
# 查看
clickhouse-compressor --stat data.bin out.log

运行截图如下所示:

如果按照默认8192的索引粒度把数据分成批次,每批次读入数据的规则:

  • 设x为批次数据的大小
  • 如果单批次数据 x < 64k,则继续读下一个批次,找到 size > 64k 则生成下一个数据块
  • 如果单批次数据 64k < x < 1M 则直接生成下一个数据块
  • 如果 x > 1M,则按照 1M 切分数据,剩下的数据继续按照上述规则执行。

数据标记

在 ClickHouse 中,mark 是索引的一部分,用于标记数据文件中数据块的开始位置。标记可以看作是一个辅助数据结构,帮助快速定位需要查询的数据块。在进行查询时,ClickHouse 不会读取整个数据文件,而是根据标记来跳过无关的数据块。


标记通常包含以下信息:


块开始的位置

块中每列的最小值和最大值

其他元数据信息

标记的粒度(即每多少行生成一个标记)可以通过配置 index_granularity 来控制。标记粒度越小,标记文件占用的空间越大,但查询性能也会越好,因为可以更精确地定位到具体的数据块。


.mrk文件:将索引primary.idx和数据文件.bin建立映射关系。

通用 hits_v1 表说明:

  • 数据标记和索引区间是对齐的,根据索引区间的下标编号,就能找到数据标记-索引编号和数据标记数值相同
  • 每一个[Column].bin都有一个[Column].mrk与之对应 .mrk文件记录数据在bin文件中的偏移量

数据标记和区间是对齐的,均按照 index_grangularity粒度间隔,可以通过索引区间的下标编号找到对应的数据标记。

每一个列字段的bin文件都有一个mrk数据标记文件,用于记录数据在bin文件的偏移量信息。

标记数据采用LRU缓存策略加快其取用速度


分区、索引、标记和压缩协同

分区(Partition)

ClickHouse 的分区机制允许将表的数据划分为多个独立的逻辑段,称为分区(partition)。每个分区中的数据可以单独存储和操作,这对处理大规模数据集和加速查询很有帮助。


分区可以基于一个或多个列定义,例如基于日期、哈希值等。创建分区的主要目的是:


提高查询效率:查询时可以只扫描特定分区,而不是整个表。

简化数据管理:分区可以独立管理,比如删除、归档和合并。

分区的常见用法是按日期或时间戳进行分区,这对时间序列数据或日志类数据非常有用。

索引(Index)

ClickHouse 的索引与传统数据库中的索引有所不同。其主要依赖于主键索引和稀疏索引来加速数据查询。


主键索引:在 MergeTree 表引擎中,主键用于决定数据的排序方式,并辅助数据查询。ClickHouse 的主键索引是一种稀疏索引,不会为每一行都创建索引项,而是为数据块创建索引项。

稀疏索引(Sparse Index):这种索引仅针对某些行进行标记,而非为每一行建立索引,从而减少了存储开销。稀疏索引与标记配合使用,使得查询时可以快速跳过无关的数据块。

此外,ClickHouse 还支持 Skip Indexes(跳过索引),用于优化复杂查询时跳过不相关的数据。这些索引类型包括 minmax、set、bloom_filter 等,适用于不同的查询场景。


标记(Marks)

标记(Marks)是 ClickHouse 中的一个重要概念,它是稀疏索引的实现基础。在每列数据的存储文件中,ClickHouse 会定期在某些行记录一个标记,记录下该行在文件中的位置。查询时,ClickHouse 会利用这些标记跳过不需要的块,从而加速查询过程。


压缩协同(Compression)

ClickHouse 的列式存储结构非常适合数据压缩。它通过对每一列的数据进行独立压缩,从而大幅减少存储空间。ClickHouse 提供了多种压缩算法,包括:


LZ4(默认):一种快速、轻量级的压缩算法,适合需要快速解压的数据。

ZSTD:一种高压缩率的算法,适合用于磁盘存储空间有限但允许较长查询时间的场景。

Delta、DoubleDelta:这些算法专为时间序列数据设计,利用相邻数值之间的差异来实现高效压缩。

写入过程

  • 生成分区目录
  • 合并分区目录
  • 生成primary.idx索引文件,每一列的bin和mrk文件

查询过程

根据分区缩小查询范围

根据数据标记、缩小查询范围

解压数据块

MergeTree的TTL

TTL:time to live 数据存活时间,TTL既可以设置在表上,也可以设置在列上,TTL指定的时间到期后删除相应的表或者列,如果同时设置了TTL,则根据先过期时间删除相应数据。


用法:

TTL time_col + INTERVAL 3 DAY

表示数据存活时间是 time_col 时间的3天后

INTERVAL 可以设定的时间:


SECOND

MINUTE

HOUR

DAY

WEEK

MONTH

QUARTER

YEAR

TTL 设置列

新建表格:

CREATE TABLE ttl_table_v1 (
  id String,
  create_time DateTime,
  code String TTL create_time + INTERVAL 10 SECOND,
  type UInt8 TTL create_time + INTERVAL 10 SECOND
) ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY id;

执行结果如下图所示:

插入数据

INSERT INTO ttl_table_v1 VALUES
('A0000', now(), 'c1', 1), 
('A0000', now() + INTERVAL 10 MINUTE, 'c1', 1);

执行结果如下图所示:

查询结果:

SELECT * FROM ttl_table_v1;

执行结果如下图所示:

手动触发数据的合并和压缩:

OPTIMIZE TABLE ttl_table_v1 FINAL;
SELECT * FROM ttl_table_v1;

看起来好像没有什么区别…

执行结果如下图:

TTL 设置表

CREATE TABLE tt1_table_v2 (
  id String,
  create_time DateTime,
  code String TTL create_time + INTERVAL 10 SECOND,
  type UInt8
) ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY create_time
TTL create_time + INTERVAL 1 DAY
;

使用 ALTER 编辑表:

ALTER TABLE tt1_table_v1 MODIFY TTL create_time + INTERVAL + 3 DAY;

运行截图如下所示:

运行结果如下所示:

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
目录
相关文章
|
23天前
|
存储 SQL 分布式计算
大数据散列分区映射到分区
大数据散列分区映射到分区
31 4
|
23天前
|
存储 负载均衡 算法
大数据散列分区计算哈希值
大数据散列分区计算哈希值
38 4
|
23天前
|
大数据 数据管理 定位技术
大数据散列分区选择分区键
大数据散列分区选择分区键
24 2
|
22天前
|
负载均衡 大数据
大数据散列分区查询频率
大数据散列分区查询频率
22 5
|
22天前
|
存储 大数据 数据处理
大数据散列分区数据分布
大数据散列分区数据分布
26 2
|
22天前
|
存储 负载均衡 监控
大数据散列分区数据分布
大数据散列分区数据分布
20 1
|
27天前
|
存储 大数据 数据管理
大数据分区简化数据维护
大数据分区简化数据维护
24 4
|
27天前
|
存储 算法 固态存储
大数据分区优化存储成本
大数据分区优化存储成本
31 4
|
28天前
|
存储 大数据 数据管理
大数据分区注意事项
大数据分区注意事项
40 5
|
28天前
|
存储 SQL 分布式计算
大数据如何增加分区
大数据如何增加分区
30 5