MergeTree 表引擎
基本介绍
MergeTree是ClickHouse特有的一种数据表存储、处理引擎。
MergeTree 支持根据主键进行索引,其中必须有一个日期字段作为主要索引字段。
同时,MergeTree拥有一种可以实时更新数据的特性(如,在写入数据的时候就可以对已写入的数据进行查询,二者不会相互阻塞),
MergeTree是ClickHouse里最先进的表引擎。
请注意: 不要将MergeTree跟Merge引擎混淆。
参数
这个引擎接受参数形式如下:
1: 日期列 (用于Partition), Date类型
2: [ 可选的 ] 示例表达式,表达式类型
3: 表的主键(Primary Key) , 元组(Tuple) 类型
4: 索引的间隔尺寸, UInt64(Granularity,请参考:稀疏索引)。
举例
不包含示例的mergeTree:
MergeTree(EventDate, (CounterID,EventDate), 8192)
其中, EventDate 是一个日期字段, CounterID是一个UInt64类型的字段
包含示例的mergeTree:
MergeTree( EventDate, intHash32 (UserId), CounterID, EventDate, intHash32(UserID)), 8192)
一个MergeTree类型的表必须有一个包含Date类型的列,在上面的例子里,该列是EventDate,这个日期列的类型必须是'Date'(而非‘DateTime’)
其中,主键为一个元组,元组中可以包含字段的组合 或 一条表达式。
这个可选的参数 示例 可以是任何的表达式,但是这个表达式必须出现在主键里。
上面的示例里使用的是一个哈希类型的userID,来伪随机的对主键里的CounterID和EventDate进行打散。换句话说,当使用了这个示例列的时候,可以伪随机的将用户打散成为均匀的子集。
合并过程
一张MergeTree表由很多个Part (单列的数据切片) 构成。每一个part按照内部对数据按照主键进行了排序。除此之外,每一个Part含有一个最小日期和最大日期。当插入数据的时候,会将插入的数据创建在一个新的Part 之中。
同时会在后台周期性的进行merge的过程,当merge的时候,很多个part会被选中,通常是最小的一些part,然后merge成为一个大的排好序的part。
换句话说,整个这个合并排序的过程是在数据插入表的时候进行的。这个merge会导致这个表总是由少量的排序好的part构成,而且这个merge本身并没有做特别多的工作。
在插入数据的过程中,属于不同的month的数据会被分割成不同的part,这些归属于不同的month的part是永远不会merge到一起的。这么做的目的是provide local data modification(比较容易做备份)。
这些part在进行合并的时候会有一个大小的阈值,所以不会有太长的merge过程。
对于每一个part,会生成一个索引文件。这个索引文件存储了表里面每一个索引块里数据的主键的value值,换句话说,这是个对有序数据的小型索引。
对列来说,在每一个索引块里的数据也写入了标记,从而让数据可以在明确的数值范围内被查找到。
当读表里的数据时,SELECT查询会被转化为要使用哪些索引。这些索引会被用在判断where条件或者prewhere条件中,来判断是否打中了这些索引区间。
因此,能够快速查询一个或多个主键范围的值。在下面的示例中,能够快速的查询一个明确的counter,指定范围的日期区间里的一个明确的counter,各种counter的集合等。
示例贴:
所有的这些示例都是用了日期索引和主键。索引会被用到复杂的表达式计算中,所以读一个组织结构化的表不会比全表扫描慢。
下面的例子中,索引不会被用到。
select count() from table where counterId = 34 or url like '%upyachka%'
日期索引只能读出包含日期查询条件的语句。然而,一个数据part可能包含很多日期的数据,在一个单一的part里,数据是按照主键进行排序的,可能不会将日期作为第一列。因此,如果查询中只是加了日期范围限定没有加主键的限定会导致遍历更多的数据行。
对于同时读和更新的表,插入操作不会阻塞读的操作。
读表的行为自动就是并行化的。
有额外的merge步骤来支持最优化的查询。
可以用一个很大的单表来不断的往里添加数据。
数据负值在mergetree这种表引擎中也是支持的,详细看下面的部分 ““data replication””