合并是什么
只有合并树系列的表才有合并这个功能。通常合并都是后台任务。合并的对象是一个表的某个分区之中的part们。合并的目的是为了将多个part合并成为一个part。 注意:一个表的跨分区的part是不能合并的。
合并的作用
1:降低磁盘的存储。当数据都存储在一个文件之中,会更好地发挥压缩算法的功能。 2:提高查询的速度。数据都存储在一个文件之中,索引文件更加少,加速查询。
合并占据的资源
合并会消耗 内存 cpu 和 磁盘。 因为合并会将原本的数据写入到一个新的文件之中,老的数据不会立即删除,老的数据会存在一定的时间,这个存在时间由具体的参数控制,所以会暂时导致磁盘数据量上涨。
合并的触发方式
一般来说,合并都是后台任务。对于后台合并而言,没有具体的参数暴露出来表示什么时候一定会进行合并。 可以执行 【optimize table 表名 final】 来手动触发合并,这个操作要慎用,很危险。
合并的实现原理
clickhouse 在后台维护了一个线程池,用于执行后台合并 和 mutation 操作。 合并的时候会选择所要进行合并的part们,然后每次从 每一个part 读取 指定的行数(由配置参数 merge_max_block_size 决定)到内存,在内存中合并,写入到磁盘,循环往复。
合并后的清除
因为合并是将原本不同目录的数据写入到一个新的目录之中,所以原本的数据会“变旧”,需要清除。 old_parts_lifetime 参数:unactive状态的part存活时间。如果unactive状态的part存活时间超过设置值,会在周期性清理之中被清除掉。 merge_tree_clear_old_parts_interval_seconds 与 merge_tree_clear_old_temporary_directories_interval_seconds 则是指定了清理的时间间隔。
合并的相关参数
-
background_pool_size :MergeTree 引擎类型的表,用于执行后台合并和mutations的线程数目。
-
number_of_free_entries_in_pool_to_execute_mutation:当合并线程池之中存在多少个空闲线程的情况下 可以执行 mutation
-
number_of_free_entries_in_pool_to_lower_max_size_of_merge: 当合并线程池之中存在多少个空闲线程的情况下会降低合并所选择的最大数据量。
-
background_merges_mutations_concurrency_ratio:一个比例,用于和 background_pool_size 参数相乘。 注意: number_of_free_entries_in_pool_to_execute_mutation 与 number_of_free_entries_in_pool_to_lower_max_size_of_merge 之中的 entries的总数 = background_pool_size * background_merges_mutations_concurrency_ratio
-
max_bytes_to_merge_at_max_space_in_pool:限制后台合并所能合并的最大数据量,可以防止大合并的出现。
-
max_parts_to_merge_at_once:一次最多可以选取多少part进行合并。
-
merge_tree_clear_old_parts_interval_seconds:每隔多少时间开始清除旧的part
-
merge_tree_clear_old_temporary_directories_interval_seconds: 每个多少时间开始清除旧的目录
-
merge_max_block_size: 合并的时候,从每个part读取的行数,用来进行合并。影响合并需要消耗的内存,默认的取值是 8192。
-
merge_selecting_sleep_ms:触发为合并选择符合条件的part的时间间隔
合并的监控
- 当前集群执行过的合并的次数
- 当前集群执行过的合并的数据量
- 一段时间内集群的合并次数
- 一段时间内 集群的合并失败次数
- 一段时间内 集群合并的数据量(未压缩) *一段时间内 合并失败的数据量 (未压缩)
- 查看一段时间内 合并失败的详细信息
- 当前正在执行的合并任务列表
- 一段时间内所有表的 平均合并耗时 最大合并耗时
- 一段时间内 每个表的合并次数 合并数据量 合并失败次数 合并失败数据量 注意:集群的合并数据量 和 合并次数 有两种统计方式,一种是 system.events 另一种是 system.part_log。system.events之中的数据 更加实时,贴合服务器的cpu变化。system.part_log表之中的数据,会出现一些延时,因为合并完成之后,数据才会写入到system.part_log。
当前集群执行过的合并次数
select * from system.events where event = 'Merge'
注意:指标是累加值。可以用prometheus 来获得一段时间内的变化。
当前集群执行过的合并数据量(未压缩)
select * from system.events where event = 'MergedUncompressedBytes'
注意:指标是累加值。可以用prometheus 来获得一段时间内的变化。
一段时间内集群的合并次数
select count(*) as merge_cnt
from
clusterAllReplicas('集群名','system.part_log')
where
event_date >= toDate('起始日期')
and event_date <= toDate(’结束日期‘)
and event_time >= ’起始时间‘
and event_time <= ’结束时间‘
and event_type = 'MergeParts'
注意:这次的统计 是从 system.part_log 表获得的,数据的波峰可能会比从system.events表之中获得的往后退一些时间,原因是 system.part_log 之中的数据,会等到合并已经完成才写入。
一段时间内 集群的合并失败次数
select
count(*) as merge_failed_cnt
from
clusterAllReplicas('集群名', 'system.part_log')
where
event_date >= toDate('开始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= '结束时间'
and event_type = 'MergeParts'
and error <> 0
一段时间内 集群合并的数据量(未压缩)
select
sum(read_bytes) as read_bytes
from clusterAllReplicas('集群名','system.part_log')
where
event_date >= toDate('起始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= '结束时间'
and event_type = 'MergeParts'
一段时间内 合并失败的数据量 (未压缩)
select
sum(read_bytes) as read_bytes
from
clusterAllReplicas('集群名','system.part_log')
where
event_date >= toDate('起始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= ‘结束时间’
and event_type = 'MergeParts'
and error <> 0
查看一段时间内 合并失败的详细信息
select
event_date, event_time, event_type, query_id, duration_ms, database, table,
partition_id, part_name, error, exception, read_rows, read_bytes
from
clusterAllReplicas('${cluster}','system.part_log')
where
event_date >= toDate('开始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= '结束时间'
and event_type = 'MergeParts'
and error <> 0
order by event_time
limit 100
当前正在执行的合并任务列表
select
*
from system.merges
where is_mutation <> 1
一段时间内所有表的 平均合并耗时 最大合并耗时
select
database,
table,
max(duration_ms) as max_duration_ms, // 最大合并耗时
avg(duration_ms) as avg_duration_ms // 平均合并耗时
from
clusterAllReplicas('集群名','system.part_log')
where
event_date >= toDate('开始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= '结束时间'
and event_type = 'MergeParts'
group by
database, table
一段时间内 每个表的合并次数 合并数据量 合并失败次数 合并失败数据量
select
database,
table,
count(*) as merge_cnt, // 合并次数
sum(if(error <> 0, 1, 0)) as merge_failed_cnt, // 合并失败次数
sum(read_bytes) as merge_bytes, // 合并数据量
sum(if(error <> 0, read_bytes, 0)) as merge_failed_bytes // 合并失败数据量
from clusterAllReplicas('集群名','system.part_log')
where
event_date >= toDate('开始日期')
and event_date <= toDate('结束日期')
and event_time >= '开始时间'
and event_time <= '结束时间'
and event_type = 'MergeParts'
group by database, table