Clickhouse 二级索引是否类似于 MySQL 普通索引?

Is Clickhouse secondary index similar to MySQL normal index?

我对何时使用二级索引感到困惑。我有以下代码脚本来定义 MergeTree Table,table 有十亿行。

create table t_mt(
 id UInt8,
 name String,
 job String,
 birthday Date,
 salary UINT8

) engine = MergeTable
primary key id
order by (id)

我会运行以下实时聚合查询:

select job, count(1), avg(salary) 
from t_mt 
group by job 
where salary > 20000

在上面的查询中,我使用了条件过滤器:salary > 20000 和分组 job。我会问在 salary 列上定义二级索引是否是一个好习惯。

我在这里要问的基本问题是我是否可以将 Clickhouse 二级索引视为 MySQL 普通索引。也就是说,如果我想按某些列进行过滤,那么我可以在该列上创建(二级)索引以加快查询速度。

不,MySQL 使用 b-tree 索引将随机查找降低到 O(log(N)) 复杂度,其中 N 是 table

中的行

Clickhouse 二级索引使用了另一种方法,它是数据跳过索引

当您尝试执行像 SELECT ... WHERE field [operation] values 这样的查询时,其中包含来自二级索引的字段并且二级索引支持应用于 field 的比较 operation,clickhouse 将读取二级索引granules 并尝试快速检查数据部分是否可以跳过搜索值,如果不是,则 clickhouse 将从数据部分读取整个列 granules

因此,二级索引不适用于分区内数据部分之间没有单调分布的高基数列

查看https://clickhouse.tech/docs/en/engines/table-engines/mergetree-family/mergetree/#table_engine-mergetree-data_skipping-indexes了解详情

Clickhouse 中的此类行为可以使用按 (salary, id) 排序的物化视图(当您将行写入原始 table 时自动填充)有效地实现。按salary查询会比skip index快很多

create materialized  view t_mt_by_salary partition by toYear(birthday) order by (salary, id)
 populate  as select  id, name , job , birthday , salary from t_mt;
select * from t_mt_by_salary where salary > 20000

没有必要使用 MySQL 类型的二级索引,因为像 clickhouse 这样的列式 OLAP 在这些类型的查询中比 MySQL 快得多。加载二级索引并进行查找在理论上可以达到 O(N log N) 的复杂度,但在实践中可能不会比完全扫描更好,因为您遇到了磁盘查找的瓶颈。

如果您的查询中有一些罕见的值或数据中有额外的结构(与索引相关),则跳过索引(clickhouse 二级索引)会有所帮助。例如。假设您过滤薪水 >200000 但 99.9% 的薪水低于 200000 - 然后 skip index 告诉您,例如下一个区块的最高薪水是 19400,所以你不需要阅读这个区块。

另一方面,如果您需要加载大约 5% 的数据,随机分布在 8000 行的颗粒(块)中,那么您可能需要扫描几乎所有的颗粒。但是您仍然可以使用按薪水排序的物化视图进行非常快速的查询。