clickhouse学习

一、参考资料

1、官方文档

2、大数据技术与数仓-clickhouse专栏

二、特点

  1. 数据压缩

  2. 列式存储

  3. 分布式查询

    数据可以在不同的分片上保存,查询可以在所有分片上并行处理

  4. 支持索引

  5. 列向量引擎,高效利用cpu资源

  6. 支持近似计算加速查询

三、引擎

MergeTree

  • 简介

    1. 执行高负载任务的最通用和最强大的表引擎
    2. 数据总会以数据片段的形式写入磁盘,且数据片段不可修改
    3. 后台线程定时将数据片段合并
  • 特点

    1. 存储的数据按照主键排序:允许创建稀疏索引,从而加快数据查询速度
    2. 支持分区,可以通过PARTITION BY语句指定分区字段
    3. 支持数据副本
    4. 支持数据采样
  • MergeTree表引擎

    建表语法:

    CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
    (
        name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
        name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
        ...
        INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
        INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
    ) ENGINE = MergeTree()
    ORDER BY expr
    [PARTITION BY expr]
    [PRIMARY KEY expr]
    [SAMPLE BY expr]
    [TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
    [SETTINGS name=value, ...]
    

    ENGINE:ENGINE = MergeTree(),MergeTree引擎没有参数

    ORDER BY:排序字段。比如ORDER BY (Col1, Col2),值得注意的是,如果没有指定主键,默认情况下 sorting key(排序字段)即为主键。如果不需要排序,则可以使用ORDER BY tuple()语法,这样的话,创建的表也就不包含主键。这种情况下,ClickHouse会按照插入的顺序存储数据。必选。

    PARTITION BY:分区字段,可选。

    PRIMARY KEY:指定主键,如果排序字段与主键不一致,可以单独指定主键字段。否则默认主键是排序字段。可选。

    SAMPLE BY:采样字段,如果指定了该字段,那么主键中也必须包含该字段。比如SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))。可选。

    TTL:数据的存活时间。在MergeTree中,可以为某个列字段或整张表设置TTL。当时间到达时,如果是列字段级别的TTL,则会删除这一列的数据;如果是表级别的TTL,则会删除整张表的数据。可选。

    SETTINGS:额外的参数配置。可选。

  • ReplacingMergeTree表引擎

    1. 建表语法:

      CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
      (
          name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
          name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
          ...
      ) ENGINE = ReplacingMergeTree([ver])
      [PARTITION BY expr]
      [ORDER BY expr]
      [PRIMARY KEY expr]
      [SAMPLE BY expr]
      [SETTINGS name=value, ...]
      
    2. 去重

      • 判断去重:

        ReplacingMergeTree在去除重复数据时,是以ORDERBY排序键为基准的,而不是PRIMARY KEY

      • 何时删除重复数据

        执行分区合并时,会触发删除重复数据,有台线程自动删除,也可以手动合并,手动合并代码

        optimize table_name final
        
      • 不同分区的重复数据不会被去重

      • 去重策略

        如果没有设置[ver]版本号,则保留同一组重复数据中的最新插入的数据;如果设置了[ver]版本号,则保留同一组重复数据中ver字段取值最大的那一行

      • optimize命令使用

        数据量大的情况下尽量不要使用,因为要消耗大量时间

  • SummingMergeTree表引擎

    1. 建表语法

      CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
      (
          name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
          name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
          ...
      ) ENGINE = SummingMergeTree([columns]) -- 指定合并汇总字段
      [PARTITION BY expr]
      [ORDER BY expr]
      [SAMPLE BY expr]
      [SETTINGS name=value, ...]
      
    2. 把具有相同主键的行合并成一行,该行包含了被合并的行中具有数值数据类型的列的汇总值

    3. 如果未指定聚合字段,会按照非主键的数值类型字段进行聚合

    4. 未指定的聚合字段,则会保留最早的那一条

  • Aggregatingmergetree表引擎

    通过预先定义的聚合函数计算数据,可以指定各种的聚合函数

  • CollapsingMergeTree表引擎

    1. 建表语法

      CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
      (
          name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
          name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
          ...
      ) ENGINE = CollapsingMergeTree(sign)
      [PARTITION BY expr]
      [ORDER BY expr]
      [SAMPLE BY expr]
      [SETTINGS name=value, ...]
      
    2. 以增代删,支持行级数据修改和删除的表引擎

    3. 通过定义一个sign标记位字段,记录数据行的状态。如果sign标记为1,则表示这是一行有效的数据;如果sign标记为-1,则表示这行数据需要被删除。当CollapsingMergeTree分区合并时,同一数据分区内,sign标记为1和-1的一组数据会被抵消删除

    4. 限制

      • 数据写入有严格的顺序,否则可能导致无法正常折叠
      • 单线程执行可以较好控制数据写入顺序,多线程不能保证
  • VersionedCollapsingMergeTree表引擎

    1. 建表语法

      CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
      (
          name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
          name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
          ...
      ) ENGINE = VersionedCollapsingMergeTree(sign, version)
      [PARTITION BY expr]
      [ORDER BY expr]
      [SAMPLE BY expr]
      [SETTINGS name=value, ...]
      
    2. 解决CollapsingMergeTree表引擎数据乱序不能折叠的问题

    3. 建表除了需要指定一个sign标识之外,还需要指定一个UInt8类型的version版本号

Log引擎

  • 场景

    主要用于快速写入小表(1百万行左右的表),然后全部读出的场景。即一次写入多次查询

  • 特点

    1. 数据存储在磁盘上,写入数据时直接追加
    2. 不支持并发读写,当表写入时,会阻塞表的读取查询
    3. 不支持原子写,当写入中断时,可能会获得带有损坏数据的表
    4. 不支持索引
    5. 不支持alter操作,例如update、delete
  • TinyLog表引擎

    1. 建表语法

      CREATE TABLE testlog (
        column_name Uint16 comment '列'
        ...
        )ENGINE=TinyLog();
      
    2. 由每一列的数据文件和一个元数据文件组成

    3. 不支持并发读数据

  • StripLog表引擎

    1. 支持并行查询
    2. 所有列数据存储在同一个文件中,减少了文件的使用数量
    3. 由3个文件组成
      • data.bin数据文件,保存所有列的数据
      • .mrk标记文件,保存了数据在data.bin文件中的位置信息,便于多线程查找数据,提高查询效率
      • size.json元数据文件,记录其余两个文件的大小
  • Log引擎表

    适用于临时数据,一次性写入,结合以上两个表引擎的优点,是Log系列引擎中性能最高的表引擎

集成引擎

  • 与其它数据存储以及处理系统集成的引擎,如 Kafka,MySQL 以及 HDFS

  • kafka引擎

    1. 建表语法

        CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
        (
          name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
          name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
          ...
        ) ENGINE = Kafka()
        SETTINGS
          kafka_broker_list = 'host:port',
          kafka_topic_list = 'topic1,topic2,...',
          kafka_group_name = 'group_name',
          kafka_format = 'data_format'[,]
          [kafka_row_delimiter = 'delimiter_symbol',]
          [kafka_schema = '',]
          [kafka_num_consumers = N,]
          [kafka_max_block_size = 0,]
          [kafka_skip_broken_messages = N,]
          [kafka_commit_every_batch = 0,]
          [kafka_thread_per_consumer = 0]
      
    2. 注意

      一旦查询完毕之后,ClickHouse会删除表内的数据,其实Kafka表引擎只是一个数据管道,可以通过物化视图的方式访问Kafka中的数据

    3. 开发流程

      一般需要三张表:

      1. kafka表,负责描述topic,消费数据和解析数据

      2. MergeTree表,存kafka数据

      3. 物化视图,用来把kafka表和MergeTree表关联起来

        create materialized view test_view to merge_tree_table as select * from kafka_table

  • 特殊引擎

    用于一些特定的功能,如 Distributed 用于分布式查询,MaterializedView 用来聚合数据,以及 Dictionary 用来查询字典数据等

    例如Distributed表引擎是分布式表的代名词,它自身不存储任何数据,数据都分散存储在某一个分片上,能够自动路由数据至集群中的各个节点,所以Distributed表引擎需要和其他数据表引擎一起协同工作

    创建分布式表:

    CREATE TABLE IF NOT EXISTS table_dist ON CLUSTER cluster_name
    (
        column1 Int32,
        column2 String
    )ENGINE = Distributed(cluster_name, db_name, local_table_name [,sharding_key]);
    /*
    cluster_name:集群名称,与集群配置中的自定义名称相对应。
    db_name:数据库名称
    local_table_name:表名称
    sharding_key:可选的,用于分片的key值,在数据写入的过程中,分布式表会依据分片key的规则,将数据分布到各个节点的本地表。
    */
    

    创建分布式表是读时检查的机制,也就是说对创建分布式表和本地表的顺序并没有强制要求

    接着就可以在每台机器上看到刚刚创建的分布式表了,然后可以在每台机器上创建一张本地表该分布式表映射的本地表了

数据副本

数据副本可以查看这里

四、开发

  • 常见问题

    1. 数据插入报错 too many parts exception

      原因:数据写入过于频繁,导致后台merge分片速度缓慢,ch拒绝数据写入

      解决:可以增加每次数据写入的batch_size(例如10万),或者增大写入数据的间隔时间

    2. 复制表变为只读

      原因:ClickHouse 无法连接 ZooKeeper 集群或 ZooKeeper 上该复制表的元数据丢失导致的,此时新数据无法插入该表

    3. 执行 JOIN 操作时内存超限

      原因:没有进行数据过滤,或者join本身的数据量很大

      解决:修改配置文件中的内存限制

    4. 直接写入方式

      1. 写入分布式表
        • 先放入本次磁盘的缓冲区,然后再分发给所有节点的MergeTree表
        • 风险
          1. 在分发给MergeTree表时节点宕机,会造成数据丢失
          2. 在节点宕机恢复后重新分发数据,可能会造成数据重复写入
          3. 分发生成更多的小文件,拖垮系统
      2. 写入MergeTree表
        • 解决数据分发问题,但依然扛不住高频的数据写入
        • 需要控制好写入数量和写入时间间隔,不然可能会造成后台合并数据分片的速度会慢于数据写入数据,造成数据写入拒绝
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容