暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

ClickHouse数据目录完全解析

ClickHouse周边 2021-06-04
5250

        之前文章有介绍过基础的MergeTree的物理存储结构,数据会按分区目录的形式保存到磁盘。本文着重介绍一些二进制文件的格式及内容。

        首先按照如下规则创建表,用于后续数据的对照查询

    #创建表
    CREATE TABLE default.ansel
    (
    `a` Int32,
    `b` Int32,
    `c` Int32,
    INDEX `idx_c` (c) TYPE minmax GRANULARITY 1
    )
    ENGINE = MergeTree
    PARTITION BY a
    ORDER BY b
    SETTINGS index_granularity=3, index_granularity_bytes = 0;

    #插入测试数据
    insert into default.ansel(a,b,c) values(3,10,4),(3,9,5),(3,8,6),(3,7,7),(3,6,8),(3,5,9),(3,4,10);
            注意:设置index_granularity_bytes = 0取消自适应索引粒度,便于后续观察mrk文件结构。
            插入后看一下测试数据如下:

            生成的数据文件如下:
      [clickhouse@localhost var/lib/clickhouse/data/default/ansel ]$ tree
      ├── 3_1_1_0
      │ ├── a.bin
      │ ├── a.mrk
      │ ├── b.bin
      │ ├── b.mrk
      │ ├── c.bin
      │ ├── checksums.txt
      │ ├── c.mrk
      │ ├── columns.txt
      │ ├── count.txt
      │ ├── minmax_a.idx
      │ ├── partition.dat
      │ ├── primary.idx
      │ ├── skp_idx_idx_c.idx
      │ └── skp_idx_idx_c.mrk
      ├── detached
      └── format_version.txt
              一般的数据目录结构如下:
        table_name                                 #表名
        ├─ partition_{index} DIR #分区目录
        │ │ # 基础文件
        │ ├─ checksums.txt BIN #各类文件的尺寸以及尺寸的散列
        │ ├─ columns.txt TXT #列信息
        │ ├─ count.txt TXT #当前分区目录下数据总行数
        │ ├─ primary.idx BIN #稀疏索引文件
        │ ├─ {column}.bin BIN #经压缩的列数据文件,以字段名命名
        │ ├─ {column}.mrk BIN #列字段标记文件
        │ ├─ {column}.mrk2 BIN #使用自适应索引间隔的标记文件
        │ │
        │ │ # 分区键文件
        │ ├─ partition.dat BIN #当前分区表达式最终值
        │ ├─ minmax_{column}.idx BIN #当前分区字段对应原始数据的最值
        │ │
        │ │ # 跳数索引文件
        │ ├─ skp_idx_{column}.idx BIN #跳数索引文件
        │ └─ skp_idx_{column}.mrk BIN #跳数索引表及文件

        └─ partition_{index}            DIR        #分区目录
        • columns.txt
                列信息文件,使用文本文件存储,用于保存分区下的列字段信息。

                记录了有多少个字段,及字段名字和类型。
        • count.txt

                计数文件,文本文件存储,用于记录当前数据分区目录下数据的总行数。

                记录了该part中row的数量。
        • primary.idx

                一级索引文件,使用二进制格式存储。

                主键索引,根据index_granularity索引粒度,每index_granularity行取一个主键列的值组合起来作为索引,例子中并没有设置PRIMARY KEY,clickhouse在这种情况下默认将ORDER BY的字段默认作为PRIMARY KEY,所以这里的primary.idx是根据b字段的数据进行固定间隔抽取的。例子中index_granularity=3,所以primary.idx中存的是4、7、10。
        • {column}.mrk

                列字段标记,使用二进制格式存储。标记文件中保存了bin文件中数据的偏移量信息,mrk文件与稀疏文件对齐,又与bin文件一一对应,所以MergeTree通过标记文件建立了primary.idx稀疏索引与bin数据文件的映射关系

                以b.mrk为例

                mrk文件分为两列,第一个值对应bin文件中压缩后数据块的偏移量,第二个值对应bin文件解压后数据块的偏移量,单位均为字节。Int32为4字节,索引粒度为3,所以数据块的偏移量是0、12、24。
                直观点可以表示成下面规则:

                所以primary.idx和mrk的行是一一对应。
        • {column}.bin

                数据文件,使用压缩格式存储,默认使用LZ4压缩格式,用于存储某一列的数据。

                以b.bin为例

                一个压缩数据块由头信息和压缩数据两部分组成。头信息固定使用9位字节表示,具体由1个UInt8(1字节)和2个UInt32(4字节)整型组成,分别代表了使用的压缩算法类型、压缩后的数据大小和压缩前的数据大小。

        1. Checksum:该bin文件的校验值,16字节。
        2. Block:数据块,包含Head和CompressedData。
        3. Head:包含CompressionMethod、CompressedSize、UncompressedSize三部分,其中CompressionMethod类型为UInt8占4字节,包含LZ4(0x82)、ZSTD(0x90)、Multipile(0x91)、Delta(0x92),CompressedSize类型为UInt32占4字节,UncompressedSize类型同样为UInt32占4字节。
        4. CompressedData:压缩数据块,默认最小65535字节/64K,最大1048576字节/1M。
                查看bin文件内容可以使用官方的clickhouse-compressor,其余bin文件都可以用这个方法
          clickhouse-compressor --decompress < 3_1_1_0/b.bin | od -An -i -w4

                  还可以通过clickhouse-compressor查看b.bin的统计信息。
            clickhouse-compressor --stat < b.bin

                    其中28表示压缩前数据大小,因为从4-10,每个数字占4字节,一共28字节,39表示压缩后数据大小,因为数据量太小,压缩也要有些必要的字节表示一些元信息,所以会比压缩前大,也可以再插入些数据再观察一下,如:
              insert into default.ansel(a,b,c) values(4,10,4),(4,9,5),(4,8,6),(4,7,7),(4,6,8),(4,5,9),(4,4,10),(4,4,11),(4,7,12),(4,4,13),(4,8,14),(4,6,15),(4,4,16),(4,6,17);

                      可以发现,压缩后是小的,如下:

                      还回到原始数据的b.bin,看下二进制文件

                      第一行16个自己就是Checksum值;
                      第二行第一个字节0x82就是压缩算法,这里就是默认的LZ4,第三到第五字节就是CompressedSize,这里centos7中安装的ck,所以是小端模式,所以要把27 00 00 00反过来看,即00 00 00 27,转换成10进制就是39,所以和上面的clickhouse-compressor中第二个数字39是一致的;继续向后看4个字节,反过来就是00 00 00 1c,即十进制的28,和上面的clickhouse-compressor中第二个数字28是一致的;再向后就涉及LZ4压缩的内容了
                      还可以通过clickhouse-compressor直接看数据的16进制存储

                      可以看到从04 00 00 00到0a 00 00 00,反过来看也就是4-10

              • partition.dat

                      用于保存当前分区下分区表达式最终生成值。

                      记录了该part的partition最终计算值,与3_1_1_0的3是一致的
              • minmax_a.idx
                      用于记录当前分区字段对应原始数据的最小值和最大值

              • checksums.txt
                      校验文件,使用二进制存储,保存了各类文件的size大小和size的哈希值,用于快速校验文件的完整性和正确性。

                      从中能看到各个column的bin和mrk文件、primary.idx、minmax_a.idx、skp_idx_c.idx、skp_idx_c.mrk的checksum值都会记录在该二进制文件中。

              近期文章推荐:
                      ClickHouse优化典藏
                      ClickHouse 之 Server Settings
                      ClickHouse那些年我们遇到过的问题
              更多精彩内容欢迎关注微信公众号


              文章转载自 ClickHouse周边,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论