深入理解ClickHouse跳数索引教程

跳数索引

影响ClickHouse查询性能的因素很多。在大多数场景中,关键因素是ClickHouse在计算查询WHERE子句条件时是否可以使用主键。因此,选择适用于最常见查询模式的主键对于表的设计至关重要。

然而,无论如何仔细地调优主键,不可避免地会出现不能有效使用它的查询用例。用户通常依赖于ClickHouse获得时间序列类型的数据,但他们通常希望根据其他业务维度(如客户id、网站URL或产品编号)分析同一批数据。在这种情况下,查询性能可能会相当差,因为应用WHERE子句条件可能需要对每个列值进行完整扫描。虽然ClickHouse在这些情况下仍然相对较快,但计算数百万或数十亿个单独的值将导致“非索引”查询的执行速度比基于主键的查询慢得多。

在传统的关系数据库中,解决这个问题的一种方法是将一个或多个“二级”索引附加到表上。这是一个b-树结构,允许数据库在O(log(n))时间内找到磁盘上所有匹配的行,而不是O(n)时间(一次表扫描),其中n是行数。但是,这种类型的二级索引不适用于ClickHouse(或其他面向列的数据库),因为磁盘上没有单独的行可以添加到索引中。

相反,ClickHouse提供了一种不同类型的索引,在特定情况下可以显著提高查询速度。这些结构被标记为跳数索引,因为它们使ClickHouse能够跳过保证没有匹配值的数据块。

基本操作

用户只能在MergeTree表引擎上使用数据跳数索引。每个跳数索引都有四个主要参数:

  • 索引名称。索引名用于在每个分区中创建索引文件。此外,在删除或具体化索引时需要将其作为参数。
  • 索引的表达式。索引表达式用于计算存储在索引中的值集。它可以是列、简单操作符、函数的子集的组合。
  • 类型。索引的类型控制计算,该计算决定是否可以跳过读取和计算每个索引块。
  • GRANULARITY。每个索引块由颗粒(granule)组成。例如,如果主表索引粒度为8192行,GRANULARITY为4,则每个索引“块”将为32768行。

当用户创建数据跳数索引时,表的每个数据部分目录中将有两个额外的文件。

  • skpidx{index_name}.idx:包含排序的表达式值。
  • skpidx{index_name}.mrk2:包含关联数据列文件中的相应偏移量。

如果在执行查询并读取相关列文件时,WHERE子句过滤条件的某些部分与跳数索引表达式匹配,ClickHouse将使用索引文件数据来确定每个相关的数据块是必须被处理还是可以被绕过(假设块还没有通过应用主键索引被排除)。这里用一个非常简单的示例:考虑以下加载了可预测数据的表。

CREATE TABLE skip_table
(
  my_key UInt64,
  my_value UInt64
)
ENGINE MergeTree primary key my_key
SETTINGS index_granularity=8192;

INSERT INTO skip_table SELECT number, intDiv(number,4096) FROM numbers(100000000);

当执行一个不使用主键的简单查询时,将扫描my_value列所有的一亿条记录:

SELECT * FROM skip_table WHERE my_value IN (125, 700)

┌─my_key─┬─my_value─┐
│ 512000125 │
│ 512001125 │
│    ... |      ... |
└────────┴──────────┘

8192 rows in set. Elapsed: 0.079 sec. Processed 100.00 million rows, 800.10 MB (1.26 billion rows/s., 10.10 GB/s.

增加一个基本的跳数索引:

ALTER TABLE skip_table ADD INDEX vix my_value TYPE set(100) GRANULARITY 2;

通常,跳数索引只应用于新插入的数据,所以仅仅添加索引不会影响上述查询。

要使已经存在的数据生效,那执行:

ALTER TABLE skip_table MATERIALIZE INDEX vix;

重跑SQL:

SELECT * FROM skip_table WHERE my_value IN (125, 700)

┌─my_key─┬─my_value─┐
│ 512000125 │
│ 512001125 │
│    ... |      ... |
└────────┴──────────┘

8192 rows in set. Elapsed: 0.051 sec. Processed 32.77 thousand rows, 360.45 KB (643.75 thousand rows/s., 7.08 MB/s.)

这次没有再去处理1亿行800MB的数据,ClickHouse只读取和分析32768行360KB的数据—4个granule的数据。

下图是更直观的展示,这就是如何读取和选择my_value为125的4096行,以及如何跳过以下行而不从磁盘读取:
在这里插入图片描述
通过在执行查询时启用跟踪,用户可以看到关于跳数索引使用情况的详细信息。在clickhouse-client中设置send_logs_level:

SET send_logs_level='trace';

这将在尝试调优查询SQL和表索引时提供有用的调试信息。上面的例子中,调试日志显示跳数索引过滤了大部分granule,只读取了两个:

<Debug> default.skip_table (933d4b2c-8cea-4bf9-8c93-c56e900eefd1) (SelectExecutor): Index `vix` has dropped 6102/6104 granules.

跳数索引类型

minmax

这种轻量级索引类型不需要参数。它存储每个块的索引表达式的最小值和最大值(如果表达式是一个元组,它分别存储元组元素的每个成员的值)。对于倾向于按值松散排序的列,这种类型非常理想。在查询处理期间,这种索引类型的开销通常是最小的。

这种类型的索引只适用于标量或元组表达式——索引永远不适用于返回数组或map数据类型的表达式。

set

这种轻量级索引类型接受单个参数max_size,即每个块的值集(0允许无限数量的离散值)。这个集合包含块中的所有值(如果值的数量超过max_size则为空)。这种索引类型适用于每组颗粒中基数较低(本质上是“聚集在一起”)但总体基数较高的列。

该索引的成本、性能和有效性取决于块中的基数。如果每个块包含大量惟一值,那么针对大型索引集计算查询条件将非常昂贵,或者由于索引超过max_size而为空,因此索引将不应用。

Bloom Filter Types

Bloom filter是一种数据结构,它允许对集合成员进行高效的是否存在测试,但代价是有轻微的误报。在跳数索引的使用场景,假阳性不是一个大问题,因为惟一的问题只是读取一些不必要的块。潜在的假阳性意味着索引表达式应该为真,否则有效的数据可能会被跳过。

因为Bloom filter可以更有效地处理大量离散值的测试,所以它们可以适用于大量条件表达式判断的场景。特别的是Bloom filter索引可以应用于数组,数组中的每个值都被测试,也可以应用于map,通过使用mapKeys或mapValues函数将键或值转换为数组。

有三种基于Bloom过滤器的数据跳数索引类型:

  • 基本的 bloom_filter 接受一个可选参数,该参数表示在0到1之间允许的“假阳性”率(如果未指定,则使用.025)。

  • 更专业的 tokenbf_v1 。需要三个参数,用来优化布隆过滤器:
    (1)过滤器的大小字节(大过滤器有更少的假阳性,有更高的存储成本)
    (2)哈希函数的个数(更多的散列函数可以减少假阳性)
    (3)布隆过滤器哈希函数的种子。有关这些参数如何影响布隆过滤器功能的更多细节,请参阅 这里 。此索引仅适用于 StringFixedStringMap 类型的数据。输入表达式被分割为由非字母数字字符分隔的字符序列。例如,列值 This is a candidate for a "full text" search 将被分割为 This is a candidate for full text search。它用于LIKE、EQUALS、in、hasToken()和类似的长字符串中单词和其他值的搜索。例如,一种可能的用途是在非结构的应用程序日志行列中搜索少量的类名或行号。

  • 更专业的 ngrambf_v1 。该索引的功能与tokenbf_v1相同。在Bloom filter设置之前需要一个额外的参数,即要索引的ngram的大小。一个ngram是长度为n的任何字符串,比如如果n是4,A short string 会被分割为 A sh sho, shor, hort, ort s, or st, r str, stri, trin, ring。这个索引对于文本搜索也很有用,特别是没有单词间断的语言,比如中文。

跳数索引函数

跳数索引核心目的是限制流行查询分析的数据量。鉴于ClickHouse数据的分析特性,这些查询的模式在大多数情况下都包含函数表达式。因此,跳数索引必须与常用函数正确交互才能提高效率。这种情况可能发生在:

  • 插入数据并将索引定义为一个函数表达式(表达式的结果存储在索引文件中)或者
  • 处理查询,并将表达式应用于存储的索引值,以确定是否排除数据块。

每种类型的跳数索引支持的函数列表可以查看下图 。通常,集合索引和基于Bloom filter的索引(另一种类型的集合索引)都是无序的,因此不能用于范围。相反,最大最小值索引在范围中工作得特别好,因为确定范围是否相交非常快。部分匹配函数LIKE、startsWith、endsWith和hasToken的有效性取决于使用的索引类型、索引表达式和数据的特定形状。
在这里插入图片描述

跳数索引的配置

有两个可用的设置可应用于跳数索引。

  • use_skip_indexes (0或1,默认为1)。不是所有查询都可以有效地使用跳过索引。如果一个特定的过滤条件可能包含很多颗粒,那么应用数据跳过索引将导致不必要的、有时甚至是非常大的成本。对于不太可能从任何跳过索引中获益的查询,将该值设置为0。
  • force_data_skipping_indexes (以逗号分隔的索引名列表)。此设置可用于防止某些类型的低效查询。在某些情况下,除非使用跳过索引,否则查询表的开销太大,如果将此设置与一个或多个索引名一起使用,则对于任何没有使用所列索引的查询将返回一个异常。这将防止编写糟糕的查询消耗服务器资源。

最佳实践

跳数索引并不直观,特别是对于来自RDMS领域并且习惯二级行索引或来自文档存储的反向索引的用户来说。要获得任何优化,应用ClickHouse数据跳数索引必须避免足够多的颗粒读取,以抵消计算索引的成本。关键是,如果一个值在一个索引块中只出现一次,就意味着整个块必须读入内存并计算,而索引开销是不必要的。

考虑以下数据分布:
在这里插入图片描述

假设主键/顺序是时间戳,并且在visitor_id上有一个索引。考虑下面的查询:

SELECT timestamp, url FROM table WHERE visitor_id = 1001

对于这种数据分布,传统的二级索引非常有利。不是读取所有的32678行来查找具有请求的 visitor_id 的5行,而是二级索引只包含5行位置,并且只从磁盘读取这5行。ClickHouse数据跳过索引的情况正好相反。无论跳转索引的类型是什么,visitor_id列中的所有32678值都将被测试。

因此,试图通过简单地向键列添加索引来加速ClickHouse查询的冲动通常是不正确的。只有在研究了其他替代方法之后,才应该使用此高级功能,例如修改主键、使用投影或使用实体化视图。即使跳数索引是合适的,也经常需要对索引和表进行仔细的调优。

在大多数情况下,一个有用的跳数索引需要主键和目标的非主列/表达式之间具有很强的相关性。如果没有相关性(如上图所示),那么在包含数千个值的块中,至少有一行满足过滤条件的可能性很高,并且只有几个块会被跳过。相反,如果主键的值范围(如一天中的时间)与潜在索引列中的值强相关(如电视观众年龄),则最小值类型的索引可能是有益的。注意,在插入数据时,可以增加这种相关性,方法是在sort /ORDER by键中包含额外的列,或者以在插入时对与主键关联的值进行分组的方式对插入进行批处理。例如,即使主键是一个包含大量站点事件的时间戳,特定site_id的所有事件也都可以被分组并由写入进程插入到一起,这将导致许多只包含少量站点id的颗粒,因此当根据特定的site_id值搜索时,可以跳过许多块。

跳数索引的另一个候选者是高基数表达式,其中任何一个值在数据中都相对稀疏。一个可能的例子是跟踪API请求中的错误代码的可观察性平台。某些错误代码虽然在数据中很少出现,但对搜索来说可能特别重要。error_code列上的set skip索引将允许绕过绝大多数不包含错误的块,从而显著改善针对错误的查询。

最后,关键的最佳实践是测试、测试、再测试。同样,与用于搜索文档的b-树二级索引或倒排索引不同,跳数索引行为是不容易预测的。将它们添加到表中会在数据摄取和查询方面产生很大的成本,这些查询由于各种原因不能从索引中受益。它们应该总是在真实世界的数据类型上进行测试,测试应该包括类型、粒度大小和其他参数的变化。测试通常会暴露仅仅通过思考不能发现的陷阱。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/61926.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

12.物联网操作系统之多任务核心

一。列表及列表项概念以及应用 1.freeRTOS列表介绍 列表项都是由链表生成&#xff0c;想要了解列表项&#xff0c;首先应该把上述的链表都要搞懂。 这是列表项的组件列表。 2.列表及列表项的定义 列表是双向链表构成&#xff0c;原因是双向链表的插入与删除效率高&#xff0c…

第一课-前提-Stable Diffusion 教程

学习 SD 的前提是电脑配置! SD 参考配置: 建议选择台式机 i5 CPU, 内存16GB,N卡 RTX3060, 8G显存以上的配置(最低配) 在此基础上的配置越高越好。 比如,cpu i7 更好,显卡能有 RTX4090 更好,32显存要能有最好,嘿嘿嘿。 如何查看自己的显卡配置? Win+R 输入 “dxdiag…

高斯过程回归 | Matlab实现高斯过程回归预测(Gaussian Process Regression)

文章目录 效果一览文章概述研究内容程序设计参考资料效果一览 文章概述 高斯过程回归 | Matlab实现高斯过程回归多输入单输出预测(Gaussian Process Regression) 研究内容 高斯过程回归(Gaussian Process Regression)是一种基于概率的非参数回归方法,用于建模输入变量和目…

TestNG中实现多线程并行,提速用例的执行时间

TestNG是一个开源自动化测试工具&#xff0c;TestNG源于Junit&#xff0c;最初用来做单元测试&#xff0c;可支持异常测试&#xff0c;忽略测试&#xff0c;超时测试&#xff0c;参数化测试和依赖测试。 除了单元测试&#xff0c;TestNG的强大功能让他在接口和UI自动化中也占有…

vue中vue-lazyload报错

1.问题&#xff1a; 说明&#xff1a;也就是版本不兼容&#xff0c;我安装的是vue2,因此需要 "vue-lazyload": "^1.2.6"或者更低 2.解决 npm i vue-lazyload1.2.6

在tensorflow分布式训练过程中突然终止(终止)

问题 这是为那些将从服务器接收渐变的员工提供的培训功能&#xff0c;在计算权重和偏差后&#xff0c;将更新的渐变发送到服务器。代码如下&#xff1a; def train():"""Train CIFAR-10 for a number of steps."""g1 tf.Graph()with g1.as_de…

shell脚本自动打包部署

1、安装git 2、使用Git克隆代码 3、安装Maven &#xff08;1&#xff09; tar -zxvf ** 解压文件 &#xff08;2&#xff09;修改配置 &#xff08;3&#xff09;source /etc/profile 重新加载一下文件 &#xff08;4&#xff09;mvn -version 查看版本号 已经安装成…

使用Python将Word文档转换为PDF的方法

摘要&#xff1a; 文介绍了如何使用Python编程语言将Word文档转换为PDF格式的方法。我们将使用python-docx和pywin32库来实现这个功能&#xff0c;这些库提供了与Microsoft Word应用程序的交互能力。 正文&#xff1a; 在现实生活和工作中&#xff0c;我们可能会遇到将Word文…

【CSS3】CSS3 2D 转换 - scale 缩放 ② ( 使用 scale 设置缩放代码示例 - 图片缩放示例 )

文章目录 一、需求分析二、代码分析三、代码示例四、执行结果 一、需求分析 默认状态下 , 界面中显示一张图片 : 当鼠标移动到 图片上时 , 显示如下效果 , 其中图片是逐渐放大的 , 有一个过渡 : 二、代码分析 上述盒子模型布局结构如下 , div 是外层父容器 , a 标签用于设置链接…

uniapp封装request请求

在基础文件里面创建一个api文件 在创建两个 js文件 http.js 里面封装 request 请求 let baseUrl https://white.51.toponet.cn; //基地址 export const request (options {}) > {//异步封装接口&#xff0c;使用Promise处理异步请求return new Promise((resolve, reject…

CNN成长路:从AlexNet到EfficientNet(01)

一、说明 在 10年的深度学习中&#xff0c;进步是多么迅速&#xff01;早在 2012 年&#xff0c;Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在&#xff0c;我们超过90%的EfficientNet架构和师生训练&#xff08;teacher-student&#xff09;。 如果我们在 Ima…

基于 Debian GNU/Linux 12 “书虫 “的Neptune 8.0 “Juna “来了

导读Neptune Linux 发行版背后的团队发布了 Neptune 8.0&#xff0c;作为这个基于 Debian 的 GNU/Linux 发行版的重大更新&#xff0c;它围绕最新的 KDE Plasma 桌面环境构建。 Neptune 8.0 被命名为 “Juna”&#xff0c;是在Neptune 7.5 发布 11 个月后发布的&#xff0c;也是…

【零基础学Rust | 基础系列 | 函数,语句和表达式】函数的定义,使用和特性

文章标题 简介一&#xff0c;函数1&#xff0c;函数的定义2&#xff0c;函数的调用3&#xff0c;函数的参数4&#xff0c;函数的返回值 二&#xff0c;语句和表达式1&#xff0c;语句2&#xff0c;表达式 总结&#xff1a; 简介 在Rust编程中&#xff0c;函数&#xff0c;语句…

Pytest测试框架1

目录&#xff1a; 1.pytest简介、安装与准备2.pytest命名规则3.pycharm配置与界面化运行4.pytest测试用例结构5.pytest测试用例断言6.pytest测试框架结构7.计算器实战 1.pytest简介、安装与准备 前言 自动化测试前&#xff0c;需要提前准备好数据&#xff0c;测试完成后&am…

操作系统复习总结1

操作系统复习总结&#xff0c;仅供笔者复习使用&#xff0c;参考教材&#xff1a; 《操作系统原理》 - 何静媛编著. 西安电子科技大学出版社《操作系统考研复习指导》2024年 - 王道论坛组编. 电子工业出版社 本文主要内容为&#xff1a;计算机系统概述&#xff1b; 计算机系…

String类及其工具类

一、String类 1.字符串对象 String str new String("hello");String对象是final修饰的&#xff0c;不可修改的&#xff0c;修改后的字符串对象是另外一个对象&#xff0c;只是修改了引用地址。每次创建都会创建一个新的对象。 2. 字面量 String s "hello&…

首批获得金融级行业云平台认证,天翼云深耕行业云

云计算下半场看什么&#xff1f; 无疑是金融、政务、制造等传统政企用户的上云与用云。随着数字经济发展和产业数字化的提速&#xff0c;上云已是政企用户推动其数字化转型不断深入的重要抓手&#xff0c;成为不可阻挡的趋势。 与互联网用户相比&#xff0c;政企用户上云极为…

uni-app——下拉框多选

一、组件components/my-selectCheckbox.vue <template><view class"uni-stat__select"><span v-if"label" class"uni-label-text">{{label &#xff1a;}}</span><view class"uni-stat-box" :class"…

mediasoup Lite ICE实现说明

目录 一. 前言 二. Lite ICE流程 三. STUN协议说明 STUN Header STUN Body 四. mediasoup Lite ICE实现源码剖析 一. 前言 ICE 是一种交互式建立连接的流程协议。ICE 有两种模式&#xff08;Full ICE 和 Lite ICE&#xff09;&#xff0c;Full ICE 要求建立连接的双方都要…

ruoyi若依 组织架构设计--[ 角色管理 ]

ruoyi若依 组织架构设计--[ 角色管理 ] 角色新增后端代码 角色修改后端代码 角色查询角色删除角色分配数据权限后端代码 角色分配用户 角色新增 后端代码 有一点&#xff0c;我认为新增的时候&#xff0c;也需要修改redis中的权限。 角色修改 后端代码 因为修改了role_menu表了…