大数据之clickhouse_clickhouse表引擎介绍

表引擎

表引擎(即表的类型)决定了:
1.数据的存储方式和位置,写到哪里以及从哪里读取数据
2.支持哪些查询以及如何支持。
3.并发数据访问。
4.索引的使用(如果存在)。
5.是否可以执行多线程请求。
6.数据复制参数。
在读取时,引擎只需要输出所请求的列,但在某些情况下,引擎可以在响应请求时部分处理数据。对于大多数正式的任务,应该使用MergeTree族中的引擎
*

日志引擎

具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的。

TinyLog引擎(数据不分块)

最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中,写入时,数据将附加到文件末尾。
该引擎没有并发控制
- 只支持并发读

  • 如果同时从表中读取和写入数据,则读取操作将抛出异常;
  • 如果同时写入多个查询中的表,则数据将被破坏。
    建表 (建表时,要跟上表引擎类型)
create table tb_tinylog(id Int8 , name String , age Int8) engine=TinyLog ;

– 插入数据

insert into tb_tinylog values(1,'马云',56),(2,'马化腾',55),(3,'马克思',123) ;

– 查询数据

SELECT * FROM tb_tinylog
┌─id─┬─name───┬─age─┐
│  1 │ 马云   │  56 │
│  2 │ 马化腾 │  55 │
│  3 │ 马克思 │ 123 │
└──┴────────┴─┘

数据在磁盘中存储的位置:
在这里插入图片描述
数据存储在机器的磁盘上,每列一个文件,插入数据向列文件的后面追加
在这里插入图片描述
再插入一条数据后, 存储列数据的文件的大小增加了

age.bin 和 id.bin,name.bin 是压缩过的对应的列的数据,sizes.json 中记录了每个 *.bin 文件的大小:
cat sizes.json
{“yandex”:{“age%2Ebin”:{“size”:“56”},“id%2Ebin”:{“size”:“56”},“name%2Ebin”:{“size”:“87”}}

这种表引擎的典型用法是 write-once:首先只写入一次数据,然后根据需要多次读取。此引擎适用于相对较小的表(建议最多1,000,000行)。如果有许多小表,则使用此表引擎是适合的,因为它比需要打开的文件更少。当拥有大量小表时,可能会导致性能低下。 不支持索引。

StripeLog(数据分块列在一起)

此引擎,每插入一次数据,就会分为一块
在你需要写入许多小数据量(小于一百万行)的表的场景下使用这个引擎。
– 建表

CREATE TABLE stripe_log_table(
    timestamp DateTime,
    message_type String,
message String)ENGINE = StripeLog ;

– 插入数据

INSERT INTO stripe_log_table VALUES (now(),'Title','多易教育') ;
INSERT INTO stripe_log_table VALUES (now(),'Subject','大数据'),(now(),'WARNING','学大数据到多易教育') ;

– 写数据
插入一条数据
StripeLog 引擎将所有列存储在一个文件中。对每一次 Insert 请求,ClickHouse 将数据块追加在表文件的末尾,逐列写入。
ClickHouse 为每张表写入以下文件:
data.bin — 数据文件。
index.mrk — 带标记的文件。标记包含了已插入的每个数据块中每列的偏移量。
StripeLog 引擎不支持 ALTER UPDATE 和 ALTER DELETE 操作。

读数据
带标记的文件使得 ClickHouse 可以并行的读取数据。这意味着 SELECT 请求返回行的顺序是不可预测的。使用 ORDER BY 子句对行进行排序。
我们使用两次 INSERT 请求从而在 data.bin 文件中创建两个数据块。
ClickHouse 在查询数据时使用多线程。每个线程读取单独的数据块并在完成后独立的返回结果行。这样的结果是,大多数情况下,输出中块的顺序和输入时相应块的顺序是不同的。例如:
select * from stripe_log_table ;
在这里插入图片描述

Log引擎总结

共同属性
数据存储在磁盘上。
写入时将数据追加在文件末尾。
不支持突变操作。
不支持索引。
这意味着 SELECT 在范围查询时效率不高。
非原子地写入数据。
如果某些事情破坏了写操作,例如服务器的异常关闭,你将会得到一张包含了损坏数据的表。

差异
Log 和 StripeLog 引擎支持:
并发访问数据的锁。
INSERT 请求执行过程中表会被锁定,并且其他的读写数据的请求都会等待直到锁定被解除。如果没有写数据的请求,任意数量的读请求都可以并发执行。
并行读取数据。
在读取数据时,ClickHouse 使用多线程。 每个线程处理不同的数据块。

Log 引擎为表中的每一列使用不同的文件。StripeLog 将所有的数据存储在一个文件中。因此 StripeLog 引擎在操作系统中使用更少的描述符,但是 Log 引擎提供更高的读性能。

TinyLog 引擎是该系列中最简单的引擎并且提供了最少的功能和最低的性能。TingLog 引擎不支持并行读取和并发数据访问,并将每一列存储在不同的文件中。它比其余两种支持并行读取的引擎的读取速度更慢,并且使用了和 Log 引擎同样多的描述符。你可以在简单的低负载的情景下使用它。

MergeTree家族引擎

MergeTree系列的表引擎是ClickHouse数据存储功能的核心。它们提供了用于弹性高性能数据检索的大多数功能:列存储自定义分区稀疏的主索引辅助数据跳过索引, 合并 , 支持随机改 , 支持副本
基本MergeTree表引擎可以被认为是单节点ClickHouse实例的默认表引擎,因为它在各种用例中通用且实用。
对于生产用途,ReplicatedMergeTree是必经之路,因为它为常规MergeTree引擎的所有功能增加了高可用性。一个额外的好处是在数据提取时自动进行重复数据删除,因此如果插入过程中出现网络问题,该软件可以安全地重试。
MergeTree系列的所有其他引擎为某些特定用例添加了额外的功能。通常,它是作为后台的其他数据操作实现的。
MergeTree引擎的主要缺点是它们很重。因此,典型的模式是没有太多。如果您需要许多小表(例如用于临时数据),请考虑使用Log engine family。
允许快速写入不断变化的对象状态。
删除后台中的旧对象状态。 这显着降低了存储体积。

该MergeTree系列(*MergeTree)的引擎和其他引擎是最强大的ClickHouse表引擎。
该MergeTree系列中的引擎旨在将大量数据插入表中。数据快速地逐个部分地写入表中,然后应用规则在后台合并这些部分。这种方法比插入期间连续重写存储中的数据效率更高。
主要特点:
存储按主键排序的数据。
这使您可以创建一个小的稀疏索引,以帮助更快地查找数据。
如果指定了分区键,则可以使用分区。
ClickHouse支持的某些分区操作比对相同数据,相同结果的常规操作更有效。ClickHouse还会自动切断在查询中指定了分区键的分区数据。这也提高了查询性能。
数据复制支持。
ReplicatedMergeTree表族提供数据复制。有关更多信息.
数据采样支持。
如有必要,可以在表中设置数据采样方法。

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 (CounterID, EventDate)。
如果PRIMARY KEY子句未明确定义主键,则ClickHouse会将排序键用作主键。
ORDER BY tuple()如果不需要排序,请使用语法。
PARTITION BY— 分区键。可选的。
要按月进行分区,请使用toYYYYMM(date_column)表达式,其中的date_column是日期类型为Date的列。此处的分区名称具有"YYYYMM"格式。
PRIMARY KEY—主键(与排序键)不同。可选的。
默认情况下,主键与排序键(由ORDER BY子句指定)相同。因此,在大多数情况下,无需指定单独的PRIMARY KEY子句。
SAMPLE BY—用于采样的表达式。可选的。
如果使用采样表达式,则主键必须包含它。范例:SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))。
TTL—规则列表,用于指定行的存储持续时间并定义磁盘和卷之间零件自动移动的逻辑。可选的。
结果必须有一个Date或一DateTime列。例:
TTL date + INTERVAL 1 DAY
规则的类型DELETE|TO DISK ‘xxx’|TO VOLUME 'xxx’指定了在满足表达式(达到当前时间)时要对零件执行的操作:删除过期的行,将零件(如果对零件中的所有行都满足表达式)移动到指定的磁盘(TO DISK ‘xxx’)或到音量(TO VOLUME ‘xxx’)。规则的默认类型为删除(DELETE)。可以指定多个规则的列表,但最多只能有一个DELETE规则。
SETTINGS—控制MergeTree(可选)行为的其他参数:
1.index_granularity—索引标记之间的最大数据行数。默认值:8192。请参见数据存储。
2.index_granularity_bytes—数据粒度的最大大小(以字节为单位)。默认值:10Mb。要仅按行数限制颗粒大小,请设置为0(不建议)。请参阅数据存储。
3.enable_mixed_granularity_parts—启用或禁用过渡以通过index_granularity_bytes设置控制颗粒尺寸。在版本19.11之前,只有index_granularity用于限制颗粒大小的设置。index_granularity_bytes从具有大行(数十和数百MB)的表中选择数据时,此设置可提高ClickHouse性能。如果您的表具有大行,则可以为表启用此设置以提高SELECT查询效率。
4.use_minimalistic_part_header_in_zookeeper— ZooKeeper中数据部件头的存储方法。如果为use_minimalistic_part_header_in_zookeeper=1,则ZooKeeper存储的数据较少。有关更多信息,请参阅“服务器配置参数”中的设置说明。
5.min_merge_bytes_to_use_direct_io—使用对存储磁盘的直接I / O访问所需的最小合并操作数据量。合并数据部分时,ClickHouse会计算要合并的所有数据的总存储量。如果卷超过min_merge_bytes_to_use_direct_io字节,ClickHouse将使用直接I / O接口(O_DIRECT选项)读取数据并将数据写入存储磁盘。如果为min_merge_bytes_to_use_direct_io = 0,则直接I / O被禁用。默认值:10 * 1024 * 1024 * 1024字节。

6.merge_with_ttl_timeout—重复与TTL合并之前的最小延迟(以秒为单位)。默认值:86400(1天)。
7.write_final_mark—启用或禁用在数据部分的末尾(最后一个字节之后)写入最终索引标记。默认值:1.不要关闭它。
8.merge_max_bloCK_size—合并操作的块中的最大行数。默认值:8192
9.storage_policy—存储策略。请参阅使用多个块设备进行数据存储。
10.min_bytes_for_wide_part,min_rows_for_wide_part—可以以Wide格式存储的数据部分中的最小字节/行数。您可以设置这些设置之一,全部或全部。请参阅数据存储。
示例
建表

create table tb_merge_tree(
id Int8 ,
name String ,
ctime Date 
)
engine=MergeTree()
order by id 
partition by name ;

插入数据

insert into tb_merge_tree values
(1,'hng','2020-08-07'),
(4,'hng','2020-08-07'),
(3,'ada','2020-08-07'),
(2,'ada','2020-08-07') ; 

指定的分区字段是name
指定的排序字段是id

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

再次插入数据

insert into tb_merge_tree values(5,'ada','2020-08-07'),(6,'hng','2020-08-07') ;

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

每批次的插入数据作为一个基础单元进行分区,区内数据按照指定的字段进行排序
进入到某个分区目录下
[root@linux04 8cc7880f023bd2c11f539b5088249423_1_1_0]# ll
total 48
-rw-r-----. 1 ClickHouse ClickHouse 361 Aug 5 14:43 cheCKsums.txt
-rw-r-----. 1 ClickHouse ClickHouse 74 Aug 5 14:43 columns.txt 所有的列
-rw-r-----. 1 ClickHouse ClickHouse 1 Aug 5 14:43 count.txt 记录数据的条数
-rw-r-----. 1 ClickHouse ClickHouse 30 Aug 5 14:43 ctime.bin
-rw-r-----. 1 ClickHouse ClickHouse 48 Aug 5 14:43 ctime.mrk2
-rw-r-----. 1 ClickHouse ClickHouse 28 Aug 5 14:43 id.bin
-rw-r-----. 1 ClickHouse ClickHouse 48 Aug 5 14:43 id.mrk2
-rw-r-----. 1 ClickHouse ClickHouse 8 Aug 5 14:43 minmax_name.idx
-rw-r-----. 1 ClickHouse ClickHouse 34 Aug 5 14:43 name.bin
-rw-r-----. 1 ClickHouse ClickHouse 48 Aug 5 14:43 name.mrk2
-rw-r-----. 1 ClickHouse ClickHouse 4 Aug 5 14:43 partition.dat
-rw-r-----. 1 ClickHouse ClickHouse 2 Aug 5 14:43 primary.idx

  • *.bin是按列保存数据的文件
  • *.mrk保存块偏移量
  • primary.idx保存主键索引

合并多次插入数据的分区
optimize table tb_merge_tree ;

在这里插入图片描述

再合并一次 optimize table tb_merge_tree ;
在这里插入图片描述

合并完以后数据在磁盘上的存储是
在这里插入图片描述

[root@linux04 8cc7880f023bd2c11f539b5088249423_1_4_1]# cat count.txt
3[root@linux04 8cc7880f023bd2c11f539b5088249423_1_4_1]#
过段时间以后CK内部自动的会删除合并前的多余的文件夹
在这里插入图片描述

ReplacingMergeTree

这个引擎是在 MergeTree 的基础上,添加了“处理重复数据”的功能该引擎和MergeTree的不同之处在于它会删除具有相同主键的重复项。数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预先作出计划。有一些数据可能仍未被处理。因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

创建表
– 创建ReplacingMergeTree表
engine=ReplacingMergeTree(version)
传入的version表示,合并时,保留version值最大的一条数据

create table tb_rep_merge_tree(
id Int8 ,
name String ,
ctime Date ,
version UInt8 
)
engine=ReplacingMergeTree(version)
order by id 
partition by name 
primary key id;

导入数据

insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_rep_merge_tree values (1, 'b','2020-08-05', 30);
insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 30);
insert into tb_rep_merge_tree values (1, 'b','2020-08-05', 10);

查询
在这里插入图片描述

合并 自行命令 optimize table tb_rep_merge_tree ;
在这里插入图片描述
在这里插入图片描述

在数据合并的时候 根据主键分区内自动的去重主键重复的数据,我们可以指定一个字段作为数据的版本,当去除重复数据的时候保留版本大的数据!
CH内部会自动的合并数据并去重重复数据 ,当然我们也可以手动的执行合并,但是每次处罚命令只能合并一个分区的数据,一般情况下等待他自己合并数据即可! 所以我们无法保证表中不存在重复主键数据

SummingMergeTree

该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度,对于不可加的列,会取一个最先出现的值。

1)建表

create table tb_summ_merge_tree(
id Int8 ,
name String ,
ctime Date ,
cost UInt8 
)
engine=SummingMergeTree(cost)
order by id 
partition by name 
primary key id;

2)导入数据

insert into tb_summ_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_summ_merge_tree values (1, 'b','2020-08-05', 30);
insert into tb_summ_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_summ_merge_tree values (1, 'a','2020-08-05', 30);
insert into tb_summ_merge_tree values (1, 'b','2020-08-05', 10);

3)查看数据
在这里插入图片描述

4)合并
在这里插入图片描述

在这里插入图片描述

CollapsingMergeTree

ClickHouse实现了CollapsingMergeTree来消除ReplacingMergeTree的限制(只删除小版本字段的问题)。该引擎要求在建表语句中指定一个标记列Sign,后台Compaction时会将主键相同、Sign相反的行进行折叠,也即删除。
CollapsingMergeTree将行按照Sign的值分为两类:Sign=1的行称之为状态行,Sign=-1的行称之为取消行。
每次需要新增状态时,写入一行状态行;需要删除状态时,则写入一行取消行。
在后台Compaction时,状态行与取消行会自动做折叠(删除)处理。而尚未进行Compaction的数据,状态行与取消行同时存在。
因此为了能够达到主键折叠(删除)的目的,需要业务层进行适当改造:
1) 执行删除操作需要写入取消行,而取消行中需要包含与原始状态行一样的数据(Sign列除外)。所以在应用层需要记录原始状态行的值,或者在执行删除操作前先查询数据库获取原始状态行;
2)由于后台Compaction时机无法预测,在发起查询时,状态行和取消行可能尚未被折叠;另外,ClickHouse无法保证primary key相同的行落在同一个节点上,不在同一节点上的数据无法折叠。因此在进行count(*)、sum(col)等聚合计算时,可能会存在数据冗余的情况。为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col * Sign)。
CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题
示例
– 创建CollapsingMergeTree表

CREATE TABLE tb_cps_merge_tree
(
    user_id UInt64,
    name String,
    age UInt8,
    sign Int8
)
ENGINE = CollapsingMergeTree(sign)
ORDER BY user_id;

– 插入状态行,注意sign一列的值为1

INSERT INTO tb_cps_merge_tree VALUES (1001,'ADA', 18, 1);

– 插入一行取消行,用于抵消上述状态行。注意sign一列的值为-1,其余值与状态行一致;并且插入一行主键相同的新状态行

INSERT INTO tb_cps_merge_tree VALUES (1001, 'ADA', 18, -1), (1001, 'MADA', 19, 1);

– 查询数据
在这里插入图片描述

– 聚合正确的没有被剔除的数据,过滤掉被剔除的数据

SELECT
    user_id,
    sum(age * sign) AS s_age
FROM tb_cps_merge_tree
GROUP BY user_id
HAVING sum(sign) > 0;

– 合并表查看数据
在这里插入图片描述

数据最终在磁盘上存储
在这里插入图片描述

在这里插入图片描述

注意:
CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题,但是状态持续变化且多线程并行写入情况下,状态行与取消行位置可能乱序,导致无法正常折叠。只有保证老的状态行在在取消行的上面, 新的状态行在取消行的下面! 如果-1的上面和下面都有多个相同主键的1那么合并后只会保留最后插入进去的一条数据,其他都会被折叠掉,当先插入一个1,再插入一个-1,合并后两条数据都会消失.

时序错乱演示
– 建表

CREATE TABLE UAct_order
(
    UserID UInt64,
    PageViews UInt8,
    Duration UInt8,
    Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;

– 先插入取消行

INSERT INTO UAct_order VALUES (4324182021466249495, 5, 146, -1);

– 后插入状态行

INSERT INTO UAct_order VALUES (4324182021466249495, 5, 146, 1);

– 强制Compaction

optimize table UAct_order final;

– 可以看到即便Compaction之后也无法进行主键折叠: 2行数据仍旧都存在。

select * from UAct_order;

在这里插入图片描述

VersionedCollapsingMergeTree

取消字段和数据版本同事使用,避免取消行数据无法删除的问题
为了解决CollapsingMergeTree乱序写入情况下无法正常折叠问题,VersionedCollapsingMergeTree表引擎在建表语句中新增了一列Version,用于在乱序情况下记录状态行与取消行的对应关系。主键相同,且Version相同、Sign相反的行,在Compaction时会被删除。
与CollapsingMergeTree类似, 为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col * Sign)。
乱序插入示例。
– 建表

CREATE TABLE tb_vscmt
(
    uid UInt64,
    name String,
    age UInt8,
    sign Int8,
    version UInt8
)
ENGINE = VersionedCollapsingMergeTree(sign, version)
ORDER BY uid;

– 先插入一行取消行,注意Signz=-1, Version=1

INSERT INTO tb_vscmt VALUES (1001, 'ADA', 18, -1, 1);

– 后插入一行状态行

INSERT INTO tb_vscmt VALUES (1001, 'ADA', 18, 1, 1),(101, 'DAD', 19, 1, 2);(101, 'DAD', 11, 1, 3); -- 数据版本
INSERT INTO tb_vscmt VALUES(101, 'DAD', 11, 1, 3) ;

查询没有合并前的数据
在这里插入图片描述

合并数据 , 查询合并后的数据 optimize table tb_vscmt ;
在这里插入图片描述

执行聚合操作 因为取消的数据被删除了 所以聚合操作两种得到的结果都正确的!

select
uid ,
sum(age * sign) as sum_age 
from
tb_vscmt
group by uid 
having  sign > 0 ;
select
uid ,
sum(age)
from
tb_vscmt
group by uid ;

数据存储
在这里插入图片描述

AggregatingMergeTree

AggregatingMergeTree也是预先聚合引擎的一种,用于提升聚合计算的性能。与SummingMergeTree的区别在于:SummingMergeTree对非主键列进行sum聚合,而AggregatingMergeTree则可以指定各种聚合函数。
AggregatingMergeTree的语法比较复杂,需要结合物化视图或ClickHouse的特殊数据类型AggregateFunction一起使用。在insert和select时,也有独特的写法和要求:写入时需要使用-State语法,查询时使用-Merge语法。
AggregateFunction(arg1 , arg2) ;
参数一 聚合函数
参数二 数据类型
先创建原始表 —插入数据—> 创建预先聚合表 --通过Insert的方式导入数据, 数据会按照指定的聚合函数聚合预先数据!
1)配合聚合函数使用
– 建立明细表

CREATE TABLE detail_table
(id UInt8,
 ctime Date,
 uid UInt64
) ENGINE = MergeTree() 
PARTITION BY toYYYYMM(ctime) 
ORDER BY (id, ctime);

– 插入明细数据

INSERT INTO detail_table VALUES(1, '2020-08-06', 1);
INSERT INTO detail_table VALUES(1, '2020-08-06', 2);
INSERT INTO detail_table VALUES(2, '2020-08-07', 1);
INSERT INTO detail_table VALUES(2, '2020-08-07', 2);

– 建立预先聚合表,
– 注意:其中UserID一列的类型为:AggregateFunction(uniq, UInt64)

CREATE TABLE agg_table
(id UInt8,
ctime Date,
uid AggregateFunction(uniq, UInt64) -- 在这个字段上进行聚合操作
) ENGINE = AggregatingMergeTree() 
PARTITION BY toYYYYMM(ctime) 
ORDER BY (id, ctime);

– 从明细表中读取数据,插入聚合表。
– 注意:子查询中使用的聚合函数为 uniqState, 对应于写入语法-State

INSERT INTO agg_table
select id, ctime, uniqState(uid)
from detail_table
group by id, ctime ;

– 不能使用普通insert语句向AggregatingMergeTree中插入数据。
– 本SQL会报错:Cannot convert UInt64 to AggregateFunction(uniq, UInt64)
INSERT INTO agg_table VALUES(1, ‘2020-08-06’, 1);

– 从聚合表中查询。
– 注意:select中使用的聚合函数为uniqMerge,对应于查询语法-Merge

SELECT
id, ctime ,
uniqMerge(uid) AS state 
FROM agg_table 
GROUP BY id, ctime;

2)使用物化视图
– 建立明细表

CREATE TABLE visits
(
    UserID UInt64,
    CounterID UInt8,
    StartDate Date,
    Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;

– 对明细表建立物化视图,该物化视图对明细表进行预先聚合
– 注意:预先聚合使用的函数分别为: sumState, uniqState。对应于写入语法-State.

CREATE MATERIALIZED VIEW visits_agg_view
ENGINE = AggregatingMergeTree() 
PARTITION BY toYYYYMM(StartDate)
ORDER BY (CounterID, StartDate)
AS SELECT
    CounterID,
    StartDate,
    sumState(Sign)    AS Visits,
    uniqState(UserID) AS Users
FROM visits
GROUP BY CounterID, StartDate;

– 插入明细数据

INSERT INTO visits VALUES(0, 0, '2019-11-11', 1);
INSERT INTO visits VALUES(1, 1, '2019-11-12', 1);

– 对物化视图进行最终的聚合操作
– 注意:使用的聚合函数为 sumMerge, uniqMerge。对应于查询语法-Merge.

SELECT
    StartDate,
    sumMerge(Visits) AS Visits,
    uniqMerge(Users) AS Users
FROM visits_agg_view
GROUP BY StartDate
ORDER BY StartDate;

– 普通函数 sum, uniq不再可以使用
– 如下SQL会报错: Illegal type AggregateFunction(sum, Int8) of argument

SELECT
    StartDate,
    sum(Visits),
    uniq(Users)
FROM visits_agg_view
GROUP BY StartDate
ORDER BY StartDate;

GraphiteMergeTree

Uid001 1,wx123,刘德华,北京
Uid001刘德华,北京,歌手,演员
Uid001 wx123,香港,演员

Uid002 1,wx323,马德华,北京
Uid002马德华,北京,歌手,演员
Uid002 wx323,香港,演员

该引擎用来对 Graphite数据进行瘦身及汇总,能减少存储空间,同时能提高Graphite数据的查询效率。

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster](
    Path String,
    Time DateTime,
    Value <Numeric_type>,
    Version <Numeric_type>
...)
ENGINE = GraphiteMergeTree(config_section)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

Graphite是一个开源实时的、显示时间序列度量数据的图形系统。Graphite并不收集度量数据本身,而是像一个数据库,通过其后端接收度量数据,然后以实时方式查询、转换、组合这些度量数据。Graphite支持内建的Web界面,它允许用户浏览度量数据和图。

Graphite有三个主要组件组成:
1)Graphite-Web
这是一个基于Django的Web应用,可以呈现图形和仪表板
2)Carbon
这是一个度量处理守护进程
3)Whisper
这是一个基于时序数据库的库
Graphite的整体架构图
在这里插入图片描述

一、Graphite的应用场景
Graphite通常用于监控基础设施级别的度量,比如CPU、内存、I/O利用率、网络吞吐量和延迟,当然Graphite在应用程序级的度量和业务级的度量方面也很不错。
Collectd是一个著名的、持续很久的Linux项目,它用于收集基础设施级的度量,在2012年被Graphite打包到项目中,作为Graphite的“写插件”。Collectd自带了很多采集插件,可以捕获从CPU到电池利用率方面度量数据,还可以度量Java和Redis方面。
通常度量不会直接发送给Graphite的后端,而是发送一次一个度量或采样给度量采集服务。StatsD是另一个开源项目,是一个著名的度量采集服务。它可以聚合接收到的采样数据,做计算统计,求平均值、标准差和其他一些统计,周期性地刷新数据到度量数据库。Graphite是StatsD的默认后端。
出于可视化的目的,内建Web界面是目前主流的选择。创建光滑的仪表板并不难,Grafana首先从Graphite获取信息,而且还可以与其它几个流行的度量数据库协同工作,比如InfluxDB、OpenTSDB和Premetheus。
当度量数据超过了预期的边界时,Graphite自身并不提供提醒功能。这方面有几个方案可以解决此问题。Cabot就是一个流行的选择,还可以使用另一个选择StackState,它提供了同样的功能。Cabot和StackState之间提醒功能的不同之处在于StackState集成了多个监控解决方案,它可以运行检查,不仅检查Graphite数据,而且检查各种以组合的监控数据。
二、Graphite的优点
1)Graphite非常快,它的架构是模块化可规模化的
2)Graphite很著名,有庞大的社区和广泛的支持
3)有很多与Graphite相互协作的开源工具
4)Graphite完成单个工作且做得很好
5)Graphite采用Apache 2.0许可证
三、Graphite的不足
1)Graphite不能对数据进行分片,因此要解决这个问题就是采用多个Graphite实例
2)Graphite的安装是一个很复杂的任务,尽管目前有了完整的Docker映像可以一次性安装Graphite及其依赖

集成引擎

Kafka
MySQL
ODBC
JDBC
HDFS
例如:通过hdfs集成引擎将clickhouse中的表存到hdfs中,也可以直接读取hdfs中的CSV格式的数据,然后通过create将读取到的数据变成表存在clickhouse中,也可以将clickhouse中的数据导入到本地.
也可以从linux本地读取数据到clickhouse中,先在clickhouse中创建一个对应格式的表,读过来时可以直接存入表中.
还可以从mysql中读取数据到clickhouse中,但是必须让mysql开放远程访问权限
具体使用可以参考官方网站:https://clickhouse.tech/docs/en/
连接jdbc:
首先配置以下依赖:

    <dependencies>
        <dependency>
            <groupId>ru.yandex.clickhouse</groupId>
            <artifactId>clickhouse-jdbc</artifactId>
            <version>0.1.54</version>
        </dependency>
    </dependencies>

代码实现:

public class Demo {
    public static void main(String[] args) throws  Exception {
        // 注册驱动
        Class.forName("ru.yandex.clickhouse.ClickHouseDriver");
        String address = "jdbc:clickhouse://linux01:8123/default";
        // 获取连接对象
        Connection conn = DriverManager.getConnection(address);
        // 获取执行SQL语句的对象
        Statement st = conn.createStatement();
        // 编写SQl 执行sql语句
        ResultSet rs = st.executeQuery("select * from tb_log");
        while(rs.next()){
            int id = rs.getInt("id");
            String name = rs.getString("name");
            System.out.println(id+"--"+name);
        }
        rs.close();
        st.close();
        conn.close();
    }
}

分布式引擎

分布式引擎首先需要搭建clickhouse集群:
搭建步骤:
1 启动zookeeper
2 在每台机器的/etc下编写配置文件/etc/metrika.xml

<yandex>
<clickhouse_remote_servers>
    <doit>
        <shard>
             <internal_replication>true</internal_replication>
            <replica>
                <host>linux01</host>
                <port>9000</port>
            </replica>
        </shard>
        <shard>
            <replica>
                <internal_replication>true</internal_replication>
                <host>linux02</host>
                <port>9000</port>
            </replica>
        </shard>
        <shard>
            <internal_replication>true</internal_replication>
            <replica>
                <host>linux03</host>
                <port>9000</port>
            </replica>
        </shard>
    </doit>
</clickhouse_remote_servers>


<zookeeper-servers>
  <node index="1">
    <host>linux01</host>
    <port>2181</port>
  </node>

  <node index="2">
    <host>linux02</host>
    <port>2181</port>
  </node>
  <node index="3">
    <host>linux03</host>
    <port>2181</port>
  </node>
</zookeeper-servers>

<macros>
<!--在哪台机器上就配哪台机器的ip主机名-->
    <replica>linux01</replica>
</macros>


<networks>
   <ip>::/0</ip>
</networks>
<clickhouse_compression>
<case>
  <min_part_size>10000000000</min_part_size>
                                             
  <min_part_size_ratio>0.01</min_part_size_ratio>                                                                                                                                       
  <method>lz4</method>
</case>
</clickhouse_compression>
</yandex>

3 修改每台机器 /etc/clikhouse-server/config.xml <listen_host>::</listen_host>
在这里插入图片描述

4 启动集群中所有的ch客户端
(如果无法启动,可以尝试重启设备,如果还是不行,就检查配置文件是否出错)

5 在每台CH的客户端中创建一个同名的普通表

create table tb_log(id UInt16, name String) ENGINE=TinyLog;

6 创建一个分布式表

create table tb_distribute(id UInt16, name String) ENGINE=Distributed(doit, default, tb_log, id);

Distributed(
参数一:配置文件中的ch机器名,
参数二:库名,
参数三:真正储存分布式数据的表(刚刚创建的同名的表名),
参数四:数据按此键分片)

7 向分布式表中插入的数据会被分散到集群中的各个节点上
向集群中某个关联的普通表中插入数据 , 在分布式表中可以查看数据

8 注意zookeeper的正常启动,一旦配好集群,每次启动ch前都要先启动zk不然登录ch时就会报错,除非删除配置文件

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值