简介
基本操作
- 索引名称。索引名称用于在每个分区中创建索引文件。此外,在删除或物化索引时,也需要将其作为参数传入。
- 索引表达式。索引表达式用于计算存储在索引中的值集合。它可以由列、简单运算符和/或由索引类型决定的一部分函数组合而成。
- TYPE。索引类型决定用于判断是否可以跳过读取并评估每个索引块的计算方式。
- GRANULARITY。每个已编制索引的块由 GRANULARITY 个粒度组成。例如,如果主表索引的粒度为 8192 行,而索引粒度为 4,那么每个已编制索引的”块”就是 32768 行。
skp_idx_{index_name}.idx,其中包含按顺序排列的表达式值skp_idx_{index_name}.mrk2,其中包含关联数据列文件中的对应偏移量。
my_value
列中的全部 1 亿个值都会被扫描:
my_value 为 125 的 4096 行是如何被读取并选中的,以及后续这些行
如何在不从磁盘读取的情况下被跳过:
你可以在执行查询时启用 trace,以查看跳过索引使用情况的详细信息。要在
clickhouse-client 中执行此操作,请设置 send_logs_level:
跳过索引类型
minmax
set
文本
hasAnyToken、hasAllTokens 等搜索函数以及所有常见文本搜索函数带来更好的性能。
详情请参阅此处的文本索引文档。
布隆过滤器类型
- 基础的 bloom_filter,接受一个可选参数,用于指定 0 到 1 之间允许的“误报”率 (如果未指定,则使用 .025) 。
-
专用的 tokenbf_v1 (已弃用) 。它接受三个参数,都用于调整所使用的布隆过滤器: (1) 过滤器的字节大小 (过滤器越大,误报越少,但会增加一些存储开销) ; (2) 应用的哈希函数个数 (同样,哈希函数越多,误报越少) ;以及 (3) 布隆过滤器哈希函数的种子。有关这些参数如何影响布隆过滤器功能的更多细节,请参见这里的计算器。
此索引仅适用于 String、FixedString 和 Map 数据类型。输入表达式会按非字母数字字符拆分为多个字符序列。例如,列值
This is a candidate for a "full text" search会包含这些标记:Thisisacandidateforfulltextsearch。它适用于在较长字符串中使用 LIKE、EQUALS、IN、hasToken() 以及类似方式搜索单词和其他值。例如,一种可能的用途是在自由格式的应用日志列中搜索少量类名或行号。 -
专用的 ngrambf_v1 (已弃用) 。此索引的工作方式与 token 索引相同。它在布隆过滤器设置之前额外接受一个参数,即要索引的 ngram 大小。ngram 是长度为
n的任意字符序列,因此,字符串A short string在 ngram 大小为 4 时会被索引为:
对于全文搜索工作负载,建议使用专用的 文本索引 (参见 Text index for full-text search) ,而不是已弃用的 tokenbf_v1 或 ngrambf_v1 索引。 文本索引 提供真正的倒排索引;与基于标记的布隆过滤器索引相比,它具有更好的搜索性能、更可预测的行为,以及更高的灵活性。
跳过索引函数
- 插入数据时,索引被定义为函数表达式 (表达式的结果会存储在索引文件中) ,或
- 处理查询时,将表达式应用于已存储的索引值,以确定是否排除该块。
跳过索引设置
- use_skip_indexes (0 或 1,默认值为 1) 。并非所有查询都能高效地使用跳过索引。如果某个过滤条件很可能会包含大多数粒度,应用数据跳过索引就会产生不必要的开销,有时甚至相当可观。对于不太可能从任何跳过索引中获益的查询,请将该值设为 0。
- force_data_skipping_indices (以逗号分隔的索引名称列表) 。此设置可用于防止某些低效查询。在某些情况下,查询某张表如果不使用跳过索引,代价就会过高;此时可通过该设置指定一个或多个索引名称,使任何未使用所列索引的查询都抛出异常。这样可以防止编写不当的查询消耗服务器资源。
跳过索引最佳实践
timestamp,并且在 visitor_id 上建有索引。请看下面这个查询:
visitor_id 列中的全部 32768 个值都会被检查。
因此,想要仅靠给关键
列添加索引来加速 ClickHouse 查询,这种直觉往往是错误的。只有在考察过其他替代方案之后,才应使用这类高级功能,例如修改主键 (参见 如何选择主键) 、使用 projections,或使用 materialized views。即使数据跳过索引确实适用,通常也仍需要对索引和表进行仔细调优。
在大多数情况下,一个有用的跳过索引要求主键与目标非主键列/表达式之间具有很强的相关性。
如果不存在相关性 (如上图所示) ,那么过滤条件在这个包含数千个值的数据块中至少匹配一行
的概率就会很高,因此能被跳过的块很少。相反,如果某个主键值范围 (例如一天中的某个时段)
与潜在索引列中的值 (例如电视观众年龄) 高度相关,那么 minmax 类型的索引
很可能会带来收益。请注意,在插入数据时,可能可以提高这种相关性,方法包括在排序/ORDER BY 键中加入额外的
列,或者采用批量插入的方式,使与主键相关的值在 on insert 时被分组。例如,某个特定 site_id 的所有事件都可以在摄取过程中分组后一起插入,即使主键
是一个包含大量站点事件的 timestamp。这样会产生许多只包含少数几个 site ids 的粒度,因此在按特定 site_id 值搜索时,许多
块都可以被跳过。
跳过索引的另一个良好候选场景,是针对高基数表达式:其中任意单个值在数据中都相对稀疏。一个例子
可能是跟踪 API 请求错误码的可观测性平台。某些错误码虽然在数据中很少见,但对于搜索可能
特别重要。在 error_code 列上建立 set 跳过索引,可以跳过绝大多数不包含
错误的块,从而显著提升面向错误分析的查询性能。
最后,最重要的最佳实践就是测试、测试、再测试。再次强调,与 b-tree 二级索引或用于文档搜索的倒排索引不同,
数据跳过索引的行为并不容易预测。将它们添加到表中,会给数据摄取以及那些由于各种原因无法从索引中获益的查询
带来显著成本。始终应当基于真实世界的数据对它们进行测试,而且测试还应
包括类型、粒度大小以及其他参数的不同组合。测试往往会揭示出仅靠
纸面推演难以发现的模式和陷阱。