在前一篇文章《ClickHouse MergeTree表引擎和建表语句》中,我们详细介绍了MergeTree的建表语句、存储结构和索引原理,本篇我们继续介绍MergeTree的另一个特性——二级索引,二级索引适用于所有MergeTree家族表引擎。在某些版本中,默认可能没有开启二级索引,可以通过下面的设置开启二级索引。

SET allow_experimental_data_skipping_indices=1;

在继续介绍之前我们先来回顾一下MergeTree的查询过程:

  1. 当我们通过主键进行查询时,会先通过primary.idx文件获取到对应的稀疏索引值,可能会有多个满足条件的稀疏索引值。例如查找 id = 1000的数据,primary.idx中刚好只有一个稀疏索引标记是 1000,那么就要把这个标记前后两个索引粒度的数据都解压出来扫描,因为满足条件的数据可能会有多个。假设这两个索引粒度区间分别是:10*8192~11*8192 - 1 和 11*8192~12*8192 - 1,简称为10和11号索引粒度。
  2. 根据mrk文件找到要查的索引粒度在各个bin文件中的偏移量。mrk第二列记录的就是每个稀疏索引行在bin文件压缩块中的偏移量,10和11号索引粒度可能在同一个压缩块中,也可能在多个压缩块中。
  3. 把第2步中查询到的压缩块全部从bin文件中取出解压,然后从第2步得到的偏移量处开始扫描判断,返回所有满足条件的数据。

大多数情况下我们都是按照主键查询的,但是如果我们查询一个非主键字段呢?或者通过一个虚拟列查询呢?例如表中有列a和b,经常需要根据 where a * b == value 来查询。此时稀疏索引就失效了,就需要全表扫描,查询效率无疑大大降低,ClickHouse MergeTree针对这种情况也给出了优化方案,就是二级索引,又叫跳数索引(Data Skipping Indexes)。

1. 创建跳数索引

跳数索引可在建表的时候指定,创建语句如下:

INDEX index_name expr TYPE type(...) GRANULARITY granularity_value

expr可以是元组,表示创建多个同类的跳数索引。一旦创建了跳数索引,在分区文件中就会出现skpi_idx_[Column].idx 和 skip_idx_[Column].mrk 文件。例如创建名称分别为a和b的minmax、set跳数索引:

CREATE TABLE table_name
(u64 UInt64,i32 Int32,s String,...INDEX a (u64 * i32, s) TYPE minmax GRANULARITY 3,INDEX b (u64 * length(s)) TYPE set(1000) GRANULARITY 4
) ENGINE = MergeTree()
...

2. 跳数索引类型

针对不同的场景,ClickHouse提供了不同类型的跳数索引。每种跳数索引都有一个 GRANULARITY 参数,表示每隔 GRANULARITY 个索引粒度 (index_granularity ) 才会生成一次跳数索引。

 注意区分 GRANULARITY 和 index_granularity 的不同。

(1)minmax

minmax顾名思义就是和分区目录下的 minmax_{column_name}.idx 文件类似,只不过不再是只有一个min/max值,例如上面的minmax跳数索引 a,表示每隔 3 * index_granularity 的区间就会记录一次 u64 * i32 和 s 的最大最小值。当我们通过s查询数据时,可以先基于minmax值判断,从而跳过大多数不需要扫描的索引粒度。

(2)set(max_rows)

保存指定表达式的去重值,尤其是对于那些重复性很高的列,例如性别、年龄段等,max_rows 参数表示在一个索引粒度内,最多记录不超过 max_rows 行,即不多于 max_rows 个去重值,max_rows=0 表示不限制。

(3)ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)

存储一个包含数据块中所有 n元短语(ngram) 的布隆过滤器(Bloom filter)。对String, FixedString 和 Map类型数据有效,可用于优化 EQUALSLIKE 和 IN表达式。

ngram表示一句话中的连续n个单词,或者一个字符串中的n个连续字符。感兴趣的同学可阅读《Word2Vector详解》。

什么是布隆过滤器呢?

本质上布隆过滤器是一种数据结构,一种比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你:某个数据一定不存在或者可能存在(注意:布隆过滤器是不能判断某条数据一定存在的,存在误报率 (false_positive) )。相比于传统的 List、Set、Map 等数据结构,布隆过滤器更高效、占用空间更少,因为不需要存储原始值,但是缺点是其返回的结果是概率性的,而不是确切的。

布隆过滤器会定义一个初始值全为0,长度为m的 bit 向量或者说 bit 数组:

然后再定义k个hash函数,使得原始数据可以映射到bit向量中(是不是和redis的bitmap很像,还记得那个怎么记录上亿用户在线状态的问题吗?)。例如,定义3个hash函数,

对于“python”得到3个hash值:1、5、6,就将bit向量中的1、5、6 bit位置1。

对于“java”得到3个hash值:2、3、9,就将bit向量中的2、3、9 bit位置1。

对于“rust”得到3个hash值:7、8、9,就将bit向量中的7、8、9 bit位置1。

可以发现,对于不同的数据,因为bit向量的长度是有限的,所以可能会出现重复的bit位被置1的情况,即不同数据之间有交集。当我们查数据的时候,例如:“go”,得到的三个hash值为:4、6、7,因为4号bit位是0,所以“go”一定不存在。如果查询数据“shell”得到的hash值是:2、5、9,虽然这个三个bit位都有数据,但是我们也不能确定“shell”一定存在。

布隆过滤器的好处是可以用较少的空间存储多条复杂数据的存在信息,但是不容易确定bit向量的长度m的值,因为m越小,bit向量就越容易被占满,越容易误报(false_positive越大),起不到过滤作用。hash函数的个数k也不容易确定,因为k越大,bit向量也越容易被占满,k越小,越容易误报,因为更容易撞车。而且,可以发现布隆过滤器是不支持删除的,因为被置1的bit位可能存储了多条数据信息,对于经常变动的数据是不合适的。

再来介绍一下ngrambf_v1的参数

  • n:ngram短语长度。
  • size_of_bloom_filter_in_bytes:布隆过滤器的大小 m,以字节为单位(可以使用较大的值,例如256或512,因为它可以很好地被压缩,并且有更强的表达能力)。
  • number_of_hash_functions:布隆过滤器中使用的哈希函数的个数 k 。
  • random_seed:布隆过滤器哈希函数的种子。

(4)tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)

跟 ngrambf_v1 类似,但是存储的是token而不是ngrams。Token是由非字母数字的符号分割的序列。不再需要ngram size参数,自动通过原始数据中的非字母数字字符切分原始数据。

(5)bloom_filter([false_positive])

为指定的列存储布隆过滤器,可用于优化 equals, notEquals, in, notIn, has, hasAny, hasAll 函数,false_positive 表示从过滤器接收到假阳性响应的概率(误报率),取值范围是 (0,1),默认值:0.025。支持数据类型:Int*UInt*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMap.

对于Map类型数据,可以使用mapKeys或mapValues函数指定是否为键或值创建索引。如:

INDEX map_key_index mapKeys(map_column) TYPE bloom_filter GRANULARITY 1
INDEX map_key_index mapValues(map_column) TYPE bloom_filter GRANULARITY 1

假设已知布隆过滤器误报率 p,插入元素个数为n,则hash函数个数 k 和布隆过滤器bit向量长度 m 为:

3. 跳数索引函数支持

在使用where条件查询的时候,如果where条件表达式中包含跳数索引列,ClickHouse会在执行函数时尝试使用索引。不同的函数对索引的支持是不同的,其中 set 索引对所有函数都生效,其他跳数索引支持如下:

 注意:参数小于ngram大小的常量函数不能被ngrambf_v1用于查询优化。例如,ngrambf_v1的参数n为5,即5元短语,则 where like 'ab%' 不能被优化。

因为布隆过滤器存在误报率,所以 ngrambf_v1tokenbf_v1, 和 bloom_filter 不能用于优化结果逻辑为False的查询。例如,下面查询语句可以优化:

s LIKE '%test%'
NOT s NOT LIKE '%test%'
s = 1
NOT s != 1
startsWith(s, 'test')

下面的语句不能被优化:

NOT s LIKE '%test%'
s NOT LIKE '%test%'
NOT s = 1
s != 1
NOT startsWith(s, 'test')

因为布隆过滤器可以明确地判断该条语句是不存在,但是却不能明确地判断一定是存在的,所以对于返回存在like后数据的块还需要全部解压扫描。

所有跳数索引的原则都是“排除法”,即尽可能的排除那些一定不满足条件的索引粒度。在写查询where条件时也要基于这一原则考虑。

ClickHouse MergeTree二级索引/跳数索引相关推荐

  1. 14|跳数索引:后起新秀ClickHouse

    14|跳数索引:后起新秀ClickHouse 你好,我是徐长龙. 通过前面的学习,我们见识到了Elasticsearch的强大功能.不过在技术选型的时候,价格也是重要影响因素.Elasticsearc ...

  2. ClickHouse MergeTree家族特殊表引擎

    在前面的文章中,我们详细介绍了ClickHouse MergeTree表引擎的使用场景.原理.数据存储结构.建表语句以及索引优化.详见<ClickHouse MergeTree表引擎和建表语句& ...

  3. 【clickhouse】MergeTree引擎的固定/自适应索引粒度

    文章目录 1.概述 2.固定索引粒度 3.自适应索引粒度 1.概述 转载:聊聊ClickHouse MergeTree引擎的固定/自适应索引粒度 我们在刚开始学习ClickHouse的MergeTre ...

  4. 设置文件副本数_ElasticSearch平滑批量缩减索引分片数实践

    一.背景    Elasticsearch作为开源分布式检索分析引擎,具有近实时的检索能力.海量数据的分布式存储能力.海量数据的近实时分析能力,目前广泛应用于国内外互联网公司.站内检索.订单类数据的多 ...

  5. MySQL创建索引跳过redo_明明我建了索引,为什么sql执行的还是这么慢?

    原标题:明明我建了索引,为什么sql执行的还是这么慢? 很多同学经常遇到这样一个问题,就是为了避免sql 执行缓慢,提前将各种可能用到的字段都添加上索引,查询的时候尽可能的使用这些字段,避免全表扫描. ...

  6. 创建二级索引_Mysql创建索引

    零:文章概要 这篇文章,主要是和大家一起去了解 索引,然后一起使用CREATE INDEX语法给数据库中的表创建一个索引. 一:先拿电话薄做个类比 假如,一个电话薄里面包含了一个城市的所有人的姓名和电 ...

  7. MySQL索引B+数(超级好看,一看就懂!!!)

    概述 索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据. 索引最形象的比喻就是图书的目录了.注意这里的大量,数据量大了索引才显得有意义,如果我想要在 [1,2,3,4] 中找到 ...

  8. 【Clickhouse】Clickhouse MergeTree家族引擎

    文章目录 1.概述 2.工作原理 2.MergeTree的存储结构 3.数据分区 4. 一级索引 5.二级索引 6.数据存储 6.1 列独立存储: 6.2 压缩数据块 7.数据标记 8.分区索引和标记 ...

  9. ClickHouse MergeTree副本表和分布式表(切片)

    在前面的文章中我们详细介绍了 MergeTree 表引擎.MergeTree 家族其他表引擎.MergeTree 二级索引等内容,clickhouse数据库都是在单节点上运行的,作为OLAP处理的大数 ...

最新文章

  1. 【imx6】Unable to find the ncurses libraries的解决办法
  2. TensorFlowSharp入门使用C#编写TensorFlow人工智能应用
  3. 神回答:编程到底难在哪里?
  4. Qt5:为窗口 创建工具栏 toobar
  5. 基于XML的IOC案例
  6. tensorflow随笔-保存与读取使用模型
  7. 计算机二级公共基础知识2020版电子版,2020年计算机二级考试公共基础知识背诵笔记...
  8. 分子动力学aimd_研究人员在沸石分子筛活性调控研究方面取得新进展
  9. android界面设计所用中文什么字体,「界面」手机界面设计字体大小知多少
  10. 2021华为软挑赛题_思路分析——实时更新,做多少更多少(四)
  11. 2021年,小傅哥の年终总结
  12. 带倍速音频播放器_带有播放列表HTML5音频播放器
  13. 简单小白vr效果制作(unity)
  14. continue语句可以用在switch语句和3种循环语句中_必须知道的C语言知识细节:break、continue语句区别...
  15. VBA自定义函数TEXTJOIN CONCAT FILTER EVALUATE
  16. reactor模式学习
  17. 26、用户 创建用户
  18. php图片上传存储源码,可实现预览
  19. 玲珑杯 1032 A-B
  20. JAVA——34.集合函数-List

热门文章

  1. 读取pb模型进行预测
  2. 创业缺乏的不是钱,是智慧
  3. 程序员的三大优良品质:偷懒,没有耐性和骄傲自大。
  4. java的发展(8-17新特性整理)
  5. k8s——通过暴漏端口实现外部访问服务
  6. 什么是业务流程重组?
  7. js获取浏览器默认语言设置并自动跳转
  8. Adb文件及文件夹操作命令
  9. EXCEL 2013中“定义名称”的命名规则
  10. ubuntu vscode use clang-format google style