• Clickhouse 原理


    Clickhouse 原理

    分区目录的合并过程

    当前 CK 版本

    select version();-- 21.8.5.7
    
    • 1

    创建新表

    CREATE TABLE dpaas_db.test_gc_part on cluster my_cluster(
        `tableName` String COMMENT '表名称',
        `traceId` String COMMENT 'UUID',
        `type` String COMMENT '消息类型',
        `scene` String COMMENT '场景',
        `createTime` datetime default toDateTime(now()) COMMENT '创建时间'
    ) ENGINE = ReplicatedMergeTree('/clickhouse/my_cluster/dpaas_db/tables/{shard}/test_gc_part/0','{replica}')
    PARTITION BY toDate(createTime)
    ORDER BY tableName
    SETTINGS index_granularity = 8192;
    
    CREATE TABLE dpaas_db.test_gc on cluster my_cluster(
        `tableName` String COMMENT '表名称',
        `traceId` String COMMENT 'UUID',
        `type` String COMMENT '消息类型',
        `scene` String COMMENT '场景',
        `createTime` datetime default toDateTime(now()) COMMENT '创建时间'
    ) ENGINE = Distributed('my_cluster','dpaas_db','test_gc_part',rand());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    查看存储目录

    [root@hadoop1 test_gc_part]# pwd
    /var/lib/clickhouse/data/dpaas_db/test_gc_part
    [root@hadoop1 test_gc_part]# ll
    total 8
    drwxr-x--- 2 clickhouse clickhouse 4096 Apr 21 19:45 detached
    -rw-r----- 1 clickhouse clickhouse    1 Apr 21 19:45 format_version.txt
    [root@hadoop1 test_gc_part]# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    插入数据

    • 插入一条当天分区的数据
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',now());
    
    • 1

    发现此时会有一个20220421_0_0_0的分区

    • 插入两条明天和后天分区的数据
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',addDays(now(),1));
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',addDays(now(),2));
    
    • 1
    • 2

    发现此时会多两个目录 20220422_0_0_020220423_0_0_0

    • 再插入一条当天分区的数据
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',now());
    
    • 1

    在这里插入图片描述

    • 在同时插入10条数据到当天分区里

    在这里插入图片描述

    此时十条数据插入后又新增了一个目录 20220421_2_2_0

    不过可以看到此时数据没有被合并

    • 手动触发合并分区

    在这里插入图片描述

    • 系统后台会定时异步删除合并后的分区(默认8分钟)

    在这里插入图片描述

    • 从表中看效果

    在这里插入图片描述

    • 最终的效果

    在这里插入图片描述

    • 在插入两条数据,一条是20220423,一条是20220420
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',addDays(now(),2));
    insert into dpaas_db.test_gc_part values('tableName','uuid','type','dataset',addDays(now(),-1));
    
    • 1
    • 2

    在这里插入图片描述

    目录规则 20220421_0_2_1

    • 20220421 是当前分区
    • 0 MinBlockNum 最小数据块编号
    • 2 MaxBlockNum 最大数据块编号
    • 0 Level 分区合并的次数

    同一分区,MinBlockNum 是递增的,不同分区不递增。默认从0开始

    当同一分区目录比较多时,会怎么样?什么时候会出现这种问题?

    当插入大批量数据时,如果单批量的条数比较少,会导致合并分区的速度小于插入分区的速度时会报错。

    clickhouse,DB::Exception: Too many parts (300). Merges are processing significantly slower than inserts.

    分区目录下的文件结构

    在这里插入图片描述

    • 真实的结构

    在这里插入图片描述
    在这里插入图片描述

    • checksums.txt :校验文件,使用二进制格式存储。它保存了primary.idxcount.txt 文件的size大小和size的hash值。用于快速校验文件的完整性和正确性

    • columns.txt : 列信息文件

    • count.txt:计数文件,当前分区下数据总量。

    • primary.idx:一级索引文件,使用二进制格式存储。用于存放稀疏索引,一张MergeTree表只能声明一次一级索引(通过ORDER BY或者PRIMARY KEY)

    • [Column].bindata.bin: 数据文件,用于存储某一列的数据。使用压缩格式存储。默认LZ4压缩格式

      • 当字段比较少的时候会将所有字段的.bin都合并到data.bin

      • 当字段多的时候会单独作为[Column].bin,例如:id.bin 。如果id是Nullable 可为空的字段,则还会多出来 [Column].null.bin

      • data.markdata.mark2 同理

    • [Column].mrkdata.mrk : 列字段标记文件,使用二进制格式存储。标记.bin文件中数据的偏移量。这里保存的是稀疏索引与.bin数据文件之间的映射关系。即首先通过稀疏索引(primary.idx)找到对应数据的偏移量信息(.mrk),再通过偏移量直接从.bin文件中读取数据

    • [Column].mrk2data.mrk2 : 如果使用了自适应大小的索引间隔,则标记文件会以 .mrk2命名。工作原理和作用与 .mrk 标记文件相同

    • partition.datminmax_[Column].idx :如果使用了 分区键,则会额外生成这两个文件。使用二进制格式存储

      • partition.dat 用于保存当前分区下分区表达式最终生成的值
      • minmax_[Column].idx 该索引文件用于记录当前分区下分区字段对应原始数据的最小和最大值。
      • 在这些分区索引的作用下,进行数据查询时能够快速跳过不必要的分区目录,从而减少需要扫描的数据范围
    • skp_idx_[Column].idx skp_idx_[Column].mrk:如果在建表语句中声明了二级索引,则会额外生成相应的二级索引与标记文件。它们同样也使用二进制存储。二级索引在ClickHouse中又称跳数索引,目前拥有minmax、set、ngrambf_v1和tokenbf_v1四种类型。最终目标与一级稀疏索引相同,都是为了进一步减少所需扫描的数据范围,以加速整个查询过程。

    count.txt:计数文件,当前分区下数据总量。

    • primary.idx:一级索引文件,使用二进制格式存储。用于存放稀疏索引,一张MergeTree表只能声明一次一级索引(通过ORDER BY或者PRIMARY KEY)

    • [Column].bindata.bin: 数据文件,用于存储某一列的数据。使用压缩格式存储。默认LZ4压缩格式

      • 当字段比较少的时候会将所有字段的.bin都合并到data.bin

      • 当字段多的时候会单独作为[Column].bin,例如:id.bin 。如果id是Nullable 可为空的字段,则还会多出来 [Column].null.bin

      • data.markdata.mark2 同理

    • [Column].mrkdata.mrk : 列字段标记文件,使用二进制格式存储。标记.bin文件中数据的偏移量。这里保存的是稀疏索引与.bin数据文件之间的映射关系。即首先通过稀疏索引(primary.idx)找到对应数据的偏移量信息(.mrk),再通过偏移量直接从.bin文件中读取数据

    • [Column].mrk2data.mrk2 : 如果使用了自适应大小的索引间隔,则标记文件会以 .mrk2命名。工作原理和作用与 .mrk 标记文件相同

    • partition.datminmax_[Column].idx :如果使用了 分区键,则会额外生成这两个文件。使用二进制格式存储

      • partition.dat 用于保存当前分区下分区表达式最终生成的值
      • minmax_[Column].idx 该索引文件用于记录当前分区下分区字段对应原始数据的最小和最大值。
      • 在这些分区索引的作用下,进行数据查询时能够快速跳过不必要的分区目录,从而减少需要扫描的数据范围
    • skp_idx_[Column].idx skp_idx_[Column].mrk:如果在建表语句中声明了二级索引,则会额外生成相应的二级索引与标记文件。它们同样也使用二进制存储。二级索引在ClickHouse中又称跳数索引,目前拥有minmax、set、ngrambf_v1和tokenbf_v1四种类型。最终目标与一级稀疏索引相同,都是为了进一步减少所需扫描的数据范围,以加速整个查询过程。

  • 相关阅读:
    基于springboot人事管理系统设计与实现
    数据结构入门
    解码器 | 基于 Transformers 的编码器-解码器模型
    Vue+springboot银首饰商城销售系统java
    全国心力衰竭日:重症心衰的黑科技——永久型人工心脏
    [附源码]Python计算机毕业设计SSM流浪动物管理系统(程序+LW)
    jquery 事件和事件对象
    优化jenkins on kubernetes构建性能慢问题
    [N1CTF 2018]eating_cms
    redis 缓存穿透、缓存击穿、缓存雪崩区别和解决方案
  • 原文地址:https://blog.csdn.net/guaoran/article/details/125563005