ClickHouse系列教程: ClickHouse系列教程


Clickhouse之MergeTree引擎分析
CRUD
Clickhouse支持查询(select)和增加(insert),但是不直接支持更新(update)和删除(delete)。
插入:MergeTree不是LSM树,因为它不包含“memtable”和“log”:插入的数据直接写入文件系统。这使得它仅适用于批量插入数据,而不是非常频繁地插入单行; 每秒一次插入很好,但是每秒一千次不行。如果有大量内容想要插入,可以使用Buffer引擎,Buffer引擎做的是把缓冲数据写入RAM,定期将其刷新到另一个表。
Clickhouse是没有update和delete命令的,根据官方的说法:ClickHouse是以性能为导向的系统,想要性能最好,但修改过的数据很难进行比较好的存储和处理。
Clickhouse通过ALTER的变种实现了UPDATE和DELETE。
Mutations(突变)是一种ALTER查询变体,允许更改或删除表中的行。突变适用于更改表中许多行的操作(单行操作也是可以的)。
该功能处于测试阶段,从1.1.54388版本开始提供。 Mutations的更新功能是版本18.12.14开始提供的,目前MergeTree引擎支持Mutations。
现有表已准备好按原样进行突变(无需转换),但在将第一个突变应用于表后,其元数据格式将与先前的服务器版本不兼容,并且回退到先前版本变得不可能。
命令如下:
ALTER TABLE [db.]table DELETE WHERE filter_expr;
ALTER TABLE [db.]table UPDATE column1 = expr1 [, …] WHERE filter_expr;
注意:更新功能不支持更新有关主键或分区键的列。
对于
MergeTree表,通过重写整个数据部分来执行突变。此操作没有原子性 - 一旦完成准备就会替换突变部分,并且在突变开始执行后,SELECT的查询将看到来自已经突变的部分的数据以及尚未突变的部分的数据。
突变按其创建顺序排序,并按顺序应用于每个部分。INSERT也部分地进行了突变 - 在提交突变之前插入表中的数据将被突变,之后插入的数据将不会被突变。请注意,突变不会以任何方式阻止INSERT。
突变本身使用系统配置文件设置异步执行。要跟踪突变的进度,您可以使用system.mutations表。即使ClickHouse服务器重新启动,成功提交的突变也将继续执行。一旦提交突变,就无法回滚突变,但如果突变由于某种原因而被卡住,则可以通过KILL MUTATION取消突变。
已完成突变的条目不会立即删除,保留条目的数量由finished_mutations_to_keep存储引擎参数确定。 旧的突变条目会被删除。
突变的具体实现过程是先使用where条件找到需要修改的parts(分区),然后重建每个part,用新的part替换旧的part。对于有大的part的表进行重建会很耗费时间(默认一个part最大大小为150G )。突变在每个小的part是原子性的。
如果不想使用突变,毕竟突变不是原子性,而且开销较大,另外一个比较好的选择是使用ReplacingMergeTree替代MergeTree。ReplacingMergeTree会删除主键相同的重复项,删除操作会在合并的过程中完成。而合并是在后台不定时地做,因此你无法预先知道数据是否合并完成。ReplacingMergeTree有个可选字段ver,类型可以为UInt*,Date或者DateTime。合并的时候,ReplacingMergeTree 从同一个分区中的所有具有相同主键的行中选择一行留下 如果 ver 列未指定,选择最后一条; 如果 ver 列已指定,选择 ver 值最大的版本留下。注意:ReplacingMergeTree去重不同分区中的相同主键的行。示例如下:
create table t2 (birth Date, id UInt16, name String, point UInt16,ver UInt8) ENGINE=ReplacingMergeTree(birth, (id, name), 8192,ver);

insert into t2(birth, id, name, point,ver) values (‘2017-04-01’, 1, ‘qwe’, 10,0);
insert into t2(birth, id, name, point,ver) values (‘2017-06-01’, 4, ‘asd’, 15,0);
insert into t2(birth, id, name, point,ver) values (‘2017-04-03’, 5, ‘zxc’, 11,0);
insert into t2(birth, id, name, point,ver) values (‘2017-04-01’, 1, ‘qwe’, 100,1);

select * from t2;

现在2个版本的内容都在,等待优化完成后只保留一个:

如果不想等待,可以在select时在表名后增加关键字FINAL ,但这样会导致查询变慢:
select birth, id, name, point, ver from t2 FINAL ;

分区规则分析
一个分区是指按指定规则逻辑组合一起的表的记录集,可以按任意标准进行分区,如按月,按日或按事件类型。为了减少需要操作的数据,每个分区都是分开存储的。访问数据时,ClickHouse 尽量使用这些分区的最小子集。
分区的使用是为了提高性能,因为分区键列的最小值和最大值存储在每个表部分中,这些值可用于修剪查询所需的表部分。但它的主要用途是促进数据操作任务(例如丢弃旧数据)。如果主键使用得很好,那么分区不会提高性能。
MergeTree引擎默认是以表中的Date字段作为分区 (partitions)的标志。如果不手动指定,Clickhouse会把Date字段的年和月自动作为分区的标准。
下面是运行实例:
drop table t;
create table t (birth Date, id UInt16, name String, point UInt16) ENGINE=MergeTree(birth, (id, name), 10);
insert into t(birth, id, name, point) values (‘2017-04-01’, 1, ‘qwe’, 10);
insert into t(birth, id, name, point) values (‘2017-06-01’, 4, ‘asd’, 15);
insert into t(birth, id, name, point) values (‘2017-04-03’, 5, ‘zxc’, 11);
所有表的分区情况都存在system.parts这个表中,查询分区情况:
SELECT name,min_date,max_date,min_block_number,max_block_number,level,partition,active
FROM system.parts
WHERE table = ‘t’;

Name是这个分区的名字,比如说20170401_20170401_1_1_0是由
min_date,分区中最小的日期:20170401
max_date,分区中最大的日期:20170401
min_block_number,数据块的最小编号
max_block_number,数据块的最大编号
level,块级别,即在由块组成的合并树中,该块在树中的深度
组成的。
最后一个参数activate是指这个分区是否处于激活状态,1为激活状态,0为非激活状态。非激活片段是那些在合并到较大片段之后剩余的源数据片段。损坏的数据片段也表示为非活动状态。
这时文件夹的目录组织如下:

其中detached 目录存放着使用 DETACH 语句从表中分离的分区片段。损坏的片段也会移到该目录,而不是删除。服务器不使用detached目录中的分区片段。
ClickHouse 大约在插入后15分钟定期报告合并操作,合并插入的数据片段。此外,你也可以使用 OPTIMIZE 语句直接执行合并:
OPTIMIZE TABLE t PARTITION 201704;
合并后再次查看分区情况:

新增一个分区,同时旧的2个分区的激活状态变为0。非合并部分将在合并后约10分钟删除:

那些有相同分区表达式值的数据片段才会合并。这意味着 你不应该用太精细的分区方案(超过一千个分区)。否则,会因为文件系统中的文件数量和需要找开的文件描述符过多,导致 SELECT 查询效率不佳。 不同分区之间的文件是永远不会合并的。

3.1 一条数据写入后,数据写入文件后有哪些类型文件?每种类型文件的存储结构是如何的(加上图示)?

文件存储结构
前面提到的这个表:
birth Date, id UInt16, name String, point UInt16
分区文件夹中的内容如下:

MergeTree表中的数据存储在“parts”中。每个部分以主键顺序存储数据(数据按主键元组的字典顺序排序)。所有表的列都存储他们的column.bin文件中。文件由压缩块组成,每个块通常是64 KB到1 MB的未压缩数据,具体取决于平均值大小。这些块由一个接一个地连续放置的列值组成,每列的列值的顺序相同(顺序由主键定义),因此当您按多列进行迭代时,您将获得相应行的值。
上图展示的birth.bin,id.bin,name.bin,point.bin这些文件中存储的就是数据文件。
主键本身是“稀疏的”。它不是针对每一行,而是针对某些范围的数据。单独的primary.idx文件具有每个第N行的主键值,其中N称为index_granularity(通常,N = 8192)。此外,对于每一列,我们都有带有“标记”的column.mrk文件,这些文件是数据文件中每个第N行的偏移量。每个标记都是一对:文件中的偏移量到压缩块的开头,以及解压缩块中的偏移量到数据的开头。通常,压缩块通过标记对齐,并且解压缩块中的偏移量为零。 primary.idx的数据始终驻留在内存中,并缓存column.mrk文件的数据。
上图展示birth.mrk, id.mrk, name.mrk, point.mrk 就是带标记的文件。
当我们要从MergeTree中的某个部分读取内容时,我们会查看primary.idx数据并查找可能包含请求数据的范围,然后查看column.mrk数据并计算从哪里开始读取这些范围的偏移量。由于稀疏性,可能会读取过多的数据。 ClickHouse不适用于高负载的简单点查询,因为必须为每个键读取具有index_granularity行的整个范围,并且必须为每列解压缩整个压缩块。我们使索引稀疏,因为我们必须能够为每个服务器维护数万亿行,而索引没有明显的内存消耗。此外,由于主键是稀疏的,因此它不是唯一的:它无法在INSERT时检查表中是否存在键。您可以在表中使用相同的键创建许多行。

3.3 执行查询的过程是如何用上以上数据?展开过程分析:索引过滤、数据读取、排序、分组

3.4 内存中维护哪些数据结构,如何被使用上的?

3.5 引擎的合并策略是如何的?

如果你新建一个不合规的MergeTree表,会报错:

Received exception from server (version 19.9.3):
Code: 42. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception: Storage MergeTree requires 3 to 4 parameters:
name of column with date,
[sampling element of primary key],
primary key expression,
index granularityMergeTree is a family of storage engines.MergeTrees are different in two ways:
- they may be replicated and non-replicated;
- they may do different actions on merge: nothing; sign collapse; sum; apply aggregete functions.So we have 14 combinations:MergeTree, CollapsingMergeTree, SummingMergeTree, AggregatingMergeTree, ReplacingMergeTree, GraphiteMergeTree, VersionedCollapsingMergeTreeReplicatedMergeTree, ReplicatedCollapsingMergeTree, ReplicatedSummingMergeTree, ReplicatedAggregatingMergeTree, ReplicatedReplacingMergeTree, ReplicatedGraphiteMergeTree, ReplicatedVersionedCollapsingMergeTreeIn most of cases, you need MergeTree or ReplicatedMergeTree.For replicated merge trees, you need to supply a path in ZooKeeper and a replica name as the first two parameters.
Path in ZooKeeper is like '/clickhouse/tables/01/' where /clickhouse/tables/ is a common prefix and 01 is a shard name.
Replica name is like 'mtstat01-1' - it may be the hostname or any suitable string identifying replica.
You may use macro substitutions for these parameters. It's like ReplicatedMergeTree('/clickhouse/tables/{shard}/', '{replica}'...
Look at the <macros> section in server configuration file.Next parameter (which is the first for unreplicated tables and the third for replicated tables) is the name of date column.
Date column must exist in the table and have type Date (not DateTime).
It is used for internal data partitioning and works like some kind of index.If your source data doesn't have a column of type Date, but has a DateTime column, you may add values for Date column while loading,or you may INSERT your source data to a table of type Log and then transform it with INSERT INTO t SELECT toDate(time) AS date, * FROM ...
If your source data doesn't have any date or time, you may just pass any constant for a date column while loading.Next parameter is optional sampling expression. Sampling expression is used to implement SAMPLE clause in query for approximate query execution.
If you don't need approximate query execution, simply omit this parameter.
Sample expression must be one of the elements of the primary key tuple. For example, if your primary key is (CounterID, EventDate, intHash64(UserID)), your sampling expression might be intHash64(UserID).Next parameter is the primary key tuple. It's like (CounterID, EventDate, intHash64(UserID)) - a list of column names or functional expressions in round brackets. If your primary key has just one element, you may omit round brackets.Careful choice of the primary key is extremely important for processing short-time queries.Next parameter is index (primary key) granularity. Good value is 8192. You have no reasons to use any other value.For the Collapsing mode, the last parameter is the name of a sign column - a special column that is used to 'collapse' rows with the same primary key while merging.For the Summing mode, the optional last parameter is a list of columns to sum while merging. This list is passed in round brackets, like (PageViews, Cost).
If this parameter is omitted, the storage will sum all numeric columns except columns participating in the primary key.For the Replacing mode, the optional last parameter is the name of a 'version' column. While merging, for all rows with the same primary key, only one row is selected: the last row, if the version column was not specified, or the last row with the maximum version value, if specified.For VersionedCollapsing mode, the last 2 parameters are the name of a sign column and the name of a 'version' column. Version column must be in primary key. While merging, a pair of rows with the same primary key and different sign may collapse.Examples:MergeTree(EventDate, (CounterID, EventDate), 8192)MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID), EventTime), 8192)CollapsingMergeTree(StartDate, intHash32(UserID), (CounterID, StartDate, intHash32(UserID), VisitID), 8192, Sign)SummingMergeTree(EventDate, (OrderID, EventDate, BannerID, PhraseID, ContextType, RegionID, PageID, IsFlat, TypeID, ResourceNo), 8192)SummingMergeTree(EventDate, (OrderID, EventDate, BannerID, PhraseID, ContextType, RegionID, PageID, IsFlat, TypeID, ResourceNo), 8192, (Shows, Clicks, Cost, CostCur, ShowsSumPosition, ClicksSumPosition, SessionNum, SessionLen, SessionCost, GoalsNum, SessionDepth))ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/hits', '{replica}', EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID), EventTime), 8192)For further info please read the documentation: https://clickhouse.yandex/
. 0 rows in set. Elapsed: 0.001 sec. 

参考资料:

  • ClickHouse 使用 - YS.Zou

ClickHouse系列教程三:MergeTree引擎分析相关推荐

  1. ClickHouse系列教程

    ClickHouse系列教程一:Debian/Ubuntu 下ClickHouse的安装和使用 ClickHouse系列教程二:使用航班飞行数据 ClickHouse系列教程三:MergeTree引擎 ...

  2. ClickHouse系列教程六:源码分析之Debug编译运行

    ClickHouse系列教程: ClickHouse系列教程 根据官方文档的编译教程:How to Build ClickHouse on Linux - ClickHouse Documentati ...

  3. ClickHouse系列教程七:centos下源码编译安装及报错解决

    ClickHouse系列教程: ClickHouse系列教程 参考上一篇博客: ClickHouse系列教程六:源码分析之Debug编译运行 先安装 gcc 8, g++ 8, cmake 3, ni ...

  4. ClickHouse系列教程二:使用航班飞行数据

    ClickHouse系列教程: ClickHouse系列教程 根据官方提供的教程:ClickHouse Quick Start Guide 先下载数据:ontime.csv.xz - Yandex.D ...

  5. ClickHouse系列教程八:从一个服务器导入4T数据到另外一个服务器

    ClickHouse系列教程: ClickHouse系列教程 遇到了一个问题,就是如何把数据从一个服务器导入到另外一个服务器. 最初的想法是把数据都导出到CSV文件,然后再从CSV文件导入,做法如下: ...

  6. ClickHouse 系列教程五:多种连接方法

    文章目录 clickhouse-client HTTP 接口 JDBC Python接口 ClickHouse系列教程: ClickHouse系列教程 clickhouse-client 你可以通过c ...

  7. ClickHouse系列教程四:允许远程连接 allow remote access

    ClickHouse系列教程: ClickHouse系列教程 先查看ClickHouse server端监听端口的状态: root@ubuntu:/var/lib/clickhouse/# lsof ...

  8. Fastify 系列教程三 (验证、序列化和生命周期)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  9. 汇川技术小型PLC梯形图编程系列教程(三):PLC系统程序与用户程序介绍

    原文链接:汇川技术小型PLC梯形图编程系列教程(三):PLC系统程序与用户程序介绍 PLC的定义 可编程逻辑控制器是种专门为在工业环境下应用而设计的数字运算操作电子系统.它采用一种可编程的存储器,在其 ...

最新文章

  1. python开多少进程合适_python多进程基础
  2. [leetcode]Trapping Rain Water @ Python
  3. java中矩阵怎么打印_在Java编程中打印二维数组或矩阵
  4. ( 设计高效算法 ) 年龄排序 Age Sort Uva 11462
  5. 短信宝 php使用,[php] 使用 短信宝 发送短信(thinkphp)
  6. python花括号代替缩进_Python 为什么甩掉累赘的花括号,使用缩进来划分代码块?...
  7. 训练日志 2019.1.14
  8. TIDB GC life time is shorter than transaction duration解决方法
  9. openglpython3d重构_python+opengl显示三维模型小程序
  10. 计算机c语言模拟考试,国家计算机二级c语言考试模拟题
  11. 华为背锅?微博大V质疑华为P30 Pro拍月亮造假 公司称误导观众已开除
  12. 排序算法java快速排序_快速排序算法--Java实现
  13. jvm垃圾收集器与内存分配策略
  14. 计算机网络方向 CCF推荐会议及期刊
  15. 数独大师级技巧_零基础入手攻克专家级数独难题实战案例
  16. 马士兵的经典名言!!!
  17. 水箱建模最小二乘法_消防水池、消防水箱
  18. 带变压器和不带变压器的RJ45
  19. spoon无法初始化至少一个步骤_通俗易懂:8大步骤图解注意力机制
  20. php解析m3u8代码,PHP解码转发M3U8 PHP读取转发M3U8的方法

热门文章

  1. Machine Learning | (3) Scikit-learn的分类器算法-k-近邻
  2. sangerbox平台使用(四)气泡图的绘制
  3. 宏基因组序列物种分类之kraken 1/2和Bracken的使用
  4. 【震惊】漱口水居然增加糖尿病,高血压发病率
  5. Microbiome: 16S rRNA基因拷贝数应该被校正吗?
  6. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、在折线图上为每个数据点添加数值标签
  7. R语言ggplot2可视化绘制分组水平并行条形图(bar plot)并为条形图内添加标签
  8. R语言将dataframe长表转化为宽表实战:使用reshape函数、使用tidyr包的spread函数、使用data.table
  9. NLP任务语义相似数据准备及实战
  10. fsl线性配准实践+核磁共振影像数据处理