Clickhouse引擎介绍

1、数据库引擎

1.1 MaterializeMysql【实验性阶段】

物化mysql引擎可以同步mysql表中的所有数据到Clickhouse。在同步过程中,Clickhouse相当于是Mysql的从机读取binlog日志。并且基于这个原理还能同步DDL和DML语句。

1
2
CREATE DATABASE databaseName 
ENGINE = MaterializeMySQL('127.0.0.1:3306', ['数据库名'], '用户名', '密码') ;

1.2 Mysql

mysql引擎相当于一个代理会帮你把语句传给mysql实例运行,然后返回执行结果给你。

1.3 Lazy

这个数据库引擎只适用于*log系列的表引擎。并且仅仅只把数据保存到内存中,过期之后会自动删除。

1.4 Atomic[默认]

该引擎是Clickhouse的默认引擎。能非阻塞的执行RENAME TABLE以及DROP语句。

2、表引擎

2.1 MergeTree

这个是clickhouse最引以为傲的表引擎。他的特点当你插入数据时,clickhouse并不会马上把数据放到一个大数据文件中。而是生成小的数据片段,在后台clickhouse会不定期的执行“合并”数据的操作。这也就是“合并树”命名的由来。其中“合并”操作的具体算法不同又将MergeTree分为了很多子类,他们都基于MergeTree,但是又有不同的特性。

特性:

  • 存储的数据都按照主键排序,这样就可以创建稀疏索引,加快查询速度。
  • 一个表中的数据还能进一步进行分区,但是要指定分区键
  • 支持数据复制,不过这个就要用到ReplicatedMergeTree
  • 支持数据采样

数据存储:

表中所有的数据都是按照主键的顺序保存在不同的数据块中。属于不同分区的数据会分配到不同的数据块。在ck的后台中会启动数据合并的操作,但是不会保证同样的主键一定会分配到同样的数据块。如果数据块是以wide格式存储的,那么每个字段都会是一个物理文件。而用compact格式保存则整个表中的数据会保存到1个物理文件中。compact格式适合哪些插入频繁但是量小的表。默认保存为wide格式。

数据块会逻辑上分为不同的颗粒,每个颗粒是clickhouse能够读取的最小单位。clickhouse会为每一个颗粒做一个标记,标记的内容是该颗粒第一行中的主键值。对于每一列,不管这一列是否包含主键,也会创建这样的标记文件。这个颗粒度的范围是可以通过index_granularityindex_granularity_bytes在建表的时候被设置的。

在clickhouse中,主键是允许被重复的,不存在唯一性。

选择主键:

主键的多少并没有做限制,不过主键越多插入速度会越慢,内存消耗也会变高。但是并不会影响查询时(select)的速度。

索引的使用

当一个查询中的条件包含一下条件之一,就可以使用到索引。

  • 一个表示与主键/分区键中的部分字段或全部字段相等/不等的比较表达式
  • 基于主键/分区键的字段上的 IN 或 固定前缀的LIKE 表达式;
  • 基于主键/分区键的字段上的某些函数;
  • 基于主键/分区键的表达式的逻辑表达式。

跳数索引

四种可用的所用类型:

  • minmax
    INDEX a ID TYPE minmax GRANULARITY 5表示记录每5个index_granularity区间数据中的最大值和最小值
  • set(max_rows)
    INDEX b(ID) TYPE set(100) GRANULARITY 5 表示该索引会记录数据中ID的取值,并且每5个index_granularity最多纪录100条
  • ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
  • tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
  • bloom_filter(bloom_filter([false_positive])

并发

支持并发访问,插入时不会影响select

2.2 Data Replication

以下几个引擎支持数据副本:

  • ReplicatedMergeTree
  • ReplicatedSummingMergeTree
  • ReplicatedReplacingMergeTree
  • ReplicatedAggregatingMergeTree
  • ReplicatedCollapsingMergeTree
  • ReplicatedVersionedCollapsingMergeTree
  • ReplicatedGraphiteMergeTree

副本是表级的,部署数据库级别(如mysql)。这意味着在一个数据库中,你可以有支持副本的表,也可以有普通表。insertalter语句都将可以被复制。CREATE, DROP, ATTACH, DETACH and RENAME不会被复制。

复制的过程依赖zookeeper集群交换信息,如果zookeeper不可用,那么所有复制表会切换为只读模式。

2.3 SummingMergeTree

集成了MergeTree的特性,区别在于当插入数据时,SummingMergeTree会合并主键相同的行,同时非主键字段进行累加汇总(列要是数字类型)。因为汇总这个动作发生在合并的时候,而合并是定期进行的。这意味着你刚刚插入的数据并不会马上汇总,而是以原本的样子存在。这就要求你执行聚合查询时依然要使用sum()group by

汇总规则:

  • 列中数值类型的值会被汇总。这些列的集合在参数 columns 中被定义。

  • 如果用于汇总的所有列中的值均为0,则该行会被删除。

  • 如果列不在主键中且无法被汇总,则会在现有的值中任选一个。

  • 主键所在的列中的值不会被汇总。

2.4 AggregatingMergeTree

会将所有排序健相同的行合并成1行,这一行会保存一系列聚合函数的结果。在建表时,表中的字段必须是AggregateFunction或者SimpleAggregateFunction这两种数据类型之一。

插入数据时必须使用insert select语句,而且select语句中必须带有State结尾的聚合函数(聚合函数组合器)。下面进行举例:

  1. 先创建一张订单表:
    1
    2
    3
    4
    5
    6
    CREATE TABLE sale_order (order_id UInt16,
    price UInt16,
    product_name String,
    create_day Date) ENGINE = MergeTree()
    ORDER BY (order_id)
    PARTITION BY toYYYYMM(create_day);
  2. 新增数据到订单表
    1
    insert into sale_order values(1,100,'Redmi K20 PRO','2019-01-26'),(2,150,'洗衣机','2019-01-26'),(3,80,'电视机','2019-01-27'),(4,20,'ipad','2019-01-27'),(5,10,'艾瑞泽gx','2019-01-27');
  3. 创建聚合表(以AggregateFunction数据类型为例)
    1
    2
    3
    4
    CREATE TABLE sale_order_aggretate (create_day Date,
    sumPrice AggregateFunction(sum,UInt16),
    uniProductName AggregateFunction(uniq,String)) ENGINE = AggregatingMergeTree()
    ORDER BY (create_day);
  4. 往聚合表新增数据
    1
    INSERT INTO sale_order_aggretate SELECT create_day ,sumState(price) as sumPrice ,uniqState(product_name) as uniProductName from sale_order group by create_day;
  5. 查询聚合表中的数据(按照创建日期分组,求每天的总销售额和卖出商品种类的数量),得到如下结果。
    1
    SELECT create_day ,sumMerge(sumPrice) as sumPrice ,uniqMerge(uniProductName)  from sale_order_aggretate group by create_day;
create_day sumPrice uniqMerge(uniProductName)
2019-01-26 250 2
2019-01-27 110 3

在这里有3个要点,

  • INSERT INTO SELECT语句中的聚合函数类型要和聚合表的字段声明的一致,同时聚合函数要使用State结尾。
  • 第五步查询聚合表时,使用的聚合函数要用Merge结尾
  • 直接查询聚合表中的数据(不用group by),会得到乱码,因为聚合表是以二进制的形式保存的聚合中间结果。

当然我们也可以将物化表设置为AggregatingMergeTree引擎。

AggregateFunctionSimpleAggregateFunction的区别:

  • AggregateFunction保存的是中间值不能直接被使用,SimpleAggregateFunction存储聚合函数的当前值,可以被直接使用。
  • 使用AggregateFunction数据类型在插入时必须使用State结尾的聚合函数,查询该字段时也要使用Merge结尾的聚合函数,而SimpleAggregateFunction则无此限制。
  • AggregateFunction支持的聚合函数比SimpleAggregateFunction多。
  • 对于同一种聚合函数优先使用SimpleAggregateFunction,他的效率比AggregateFunction高。

2.5 ReplacingMergeTree

该表会在合并时删除排序健相同的重复数据。因为合并是不定期的,所以ReplacingMergeTree也不能保证表中一定不存在重复数据。当然你也在新增完数据之后手动触发合并。

2.6 Log系列

log系列引擎因为只适合小数据(1百万行数据左右)的小表使用,在正式应用中很少,所以不再多做介绍。

原文链接:https://www.jdkdownload.com/clickhouse/engine.html