工程建设监理网站百度指数首页
web/
2025/10/1 4:08:10/
文章来源:
工程建设监理网站,百度指数首页,长宁网站建设优化seo,专业建站公司服务在本文中#xff0c;我们将深入研究ClickHouse索引。我们将对此进行详细说明和讨论#xff1a;
ClickHouse的索引与传统的关系数据库有何不同ClickHouse是怎样构建和使用主键稀疏索引的ClickHouse索引的最佳实践
您可以选择在自己的机器上执行本文给出的所有Clickhouse SQL…在本文中我们将深入研究ClickHouse索引。我们将对此进行详细说明和讨论
ClickHouse的索引与传统的关系数据库有何不同ClickHouse是怎样构建和使用主键稀疏索引的ClickHouse索引的最佳实践
您可以选择在自己的机器上执行本文给出的所有Clickhouse SQL语句和查询。 note 这篇文章主要关注稀疏索引。 一、数据集
在本文中我们将使用一个匿名的web流量数据集。
我们将使用样本数据集中的887万行(事件)的子集。未压缩的数据大小为887万个事件和大约700mb。当存储在ClickHouse时压缩为200mb。在我们的子集中每行包含三列表示在特定时间(EventTime列)单击URL (URL列)的互联网用户(UserID列)。
通过这三个列我们已经可以制定一些典型的web分析查询如
某个用户点击次数最多的前10个url是什么点击某个URL次数最多的前10名用户是谁用户点击特定URL的最频繁时间(比如一周中的几天)是什么
二、测试环境
本文档中给出的所有运行时数据都是在带有Apple M1 Pro芯片和16GB RAM的MacBook Pro上本地运行ClickHouse 22.2.1。
三、全表扫描
为了了解在没有主键的情况下如何对数据集执行查询我们通过执行以下SQL DDL语句(使用MergeTree表引擎)创建了一个表 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span span stylecolor:#569cd6TABLE/span hits_NoPrimaryKey
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanUserIDspan stylecolor:#d4d4d4/span UInt32span stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanURLspan stylecolor:#d4d4d4/span Stringspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanEventTimespan stylecolor:#d4d4d4/span span stylecolor:#569cd6DateTime/span
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTree
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span tuplespan stylecolor:#d4d4d4(/spanspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 接下来使用以下插入SQL将命中数据集的一个子集插入到表中。这个SQL使用URL表函数和类型推断从clickhouse.com加载一个数据集的一部分数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6INSERT/span span stylecolor:#569cd6INTO/span hits_NoPrimaryKey span stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe intHash32span stylecolor:#d4d4d4(/spanc11::UInt64span stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c15 span stylecolor:#569cd6AS/span URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c5 span stylecolor:#569cd6AS/span EventTime
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span urlspan stylecolor:#d4d4d4(/spanspan stylecolor:#ce9178https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4!/span span stylecolor:#ce9178/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfeOk.
/span
span stylecolor:#9cdcfe0 rows in set. Elapsed: 145.993 sec. Processed 8.87 million rows, 18.40 GB (60.78 thousand rows/s., 126.06 MB/s.)
/span/code/span/span/span ClickHouse客户端输出了执行结果插入了887万行数据。
最后为了简化本文后面的讨论并使图表和结果可重现我们使用FINAL关键字optimize该表 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6OPTIMIZE/span span stylecolor:#569cd6TABLE/span hits_NoPrimaryKey FINALspan stylecolor:#d4d4d4;/span
/span/code/span/span/span note 一般来说不需要也不建议在加载数据后立即执行optimize。对于这个示例为什么需要这样做是很明显的。 现在我们执行第一个web分析查询。以下是用户id为749927693的互联网用户点击次数最多的前10个url span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span URLspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6as/span Count
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_NoPrimaryKey
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span UserID span stylecolor:#d4d4d4/span span stylecolor:#b5cea8749927693/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─URL────────────────────────────┬─Count─┐
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-barana.. │ 170 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-id371...│ 52 │
/spanspan stylecolor:#9cdcfe│ http://public_search │ 45 │
/spanspan stylecolor:#9cdcfe│ http://kovrik-medvedevushku-...│ 36 │
/spanspan stylecolor:#9cdcfe│ http://forumal │ 33 │
/spanspan stylecolor:#9cdcfe│ http://korablitz.ru/L_1OFFER...│ 14 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-id371...│ 14 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-john-D...│ 13 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-john-D...│ 10 │
/spanspan stylecolor:#9cdcfe│ http://wot/html?page/23600_m...│ 9 │
/spanspan stylecolor:#9cdcfe└────────────────────────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.022 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 8.87 million rows,
/span/spanspan stylecolor:#9cdcfe70.45 MB (398.53 million rows/s., 3.17 GB/s.)
/span/code/span/span/span ClickHouse客户端输出表明ClickHouse执行了一个完整的表扫描我们的表的887万行中的每一行都被加载到ClickHouse中这不是可扩展的。
为了使这种(方式)更有效和更快我们需要使用一个具有适当主键的表。这将允许ClickHouse自动(基于主键的列)创建一个稀疏的主索引然后可以用于显著加快我们示例查询的执行。 四、包含主键的表
创建一个包含联合主键UserID和URL列的表 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span span stylecolor:#569cd6TABLE/span hits_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanUserIDspan stylecolor:#d4d4d4/span UInt32span stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanURLspan stylecolor:#d4d4d4/span Stringspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanEventTimespan stylecolor:#d4d4d4/span span stylecolor:#569cd6DateTime/span
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTree
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span span stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4,/span URLspan stylecolor:#d4d4d4)/span
/span/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span span stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4,/span URLspan stylecolor:#d4d4d4,/span EventTimespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfeSETTINGS index_granularity span stylecolor:#d4d4d4/span span stylecolor:#b5cea88192/spanspan stylecolor:#d4d4d4,/span index_granularity_bytes span stylecolor:#d4d4d4/span span stylecolor:#b5cea80/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span DDL详情
上面DDL语句中的主键会基于两个指定的键列创建主索引。
插入数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6INSERT/span span stylecolor:#569cd6INTO/span hits_UserID_URL span stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe intHash32span stylecolor:#d4d4d4(/spanc11::UInt64span stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c15 span stylecolor:#569cd6AS/span URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c5 span stylecolor:#569cd6AS/span EventTime
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span urlspan stylecolor:#d4d4d4(/spanspan stylecolor:#ce9178https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4!/span span stylecolor:#ce9178/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe0 rows in set. Elapsed: 149.432 sec. Processed 8.87 million rows, 18.40 GB (59.38 thousand rows/s., 123.16 MB/s.)
/span/code/span/span/span optimize表 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6OPTIMIZE/span span stylecolor:#569cd6TABLE/span hits_UserID_URL FINALspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 我们可以使用下面的查询来获取关于表的元数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe part_typespan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe pathspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableQuantityspan stylecolor:#d4d4d4(/spanspan stylecolor:#569cd6rows/spanspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span span stylecolor:#569cd6rows/spanspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spandata_uncompressed_bytesspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span data_uncompressed_bytesspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spandata_compressed_bytesspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span data_compressed_bytesspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spanprimary_key_bytes_in_memoryspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span primary_key_bytes_in_memoryspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe marksspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spanbytes_on_diskspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span bytes_on_disk
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span systemspan stylecolor:#d4d4d4./spanparts
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span span stylecolor:#d4d4d4(/spanspan stylecolor:#569cd6table/span span stylecolor:#d4d4d4/span span stylecolor:#ce9178hits_UserID_URL/spanspan stylecolor:#d4d4d4)/span span stylecolor:#d4d4d4AND/span span stylecolor:#d4d4d4(/spanactive span stylecolor:#d4d4d4/span span stylecolor:#b5cea81/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfeFORMAT Verticalspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfepart_type: Wide
/spanspan stylecolor:#9cdcfepath: ./store/d9f/d9f36a1a-d2e6-46d4-8fb5-ffe9ad0d5aed/all_1_9_2/
/spanspan stylecolor:#9cdcferows: 8.87 million
/spanspan stylecolor:#9cdcfedata_uncompressed_bytes: 733.28 MiB
/spanspan stylecolor:#9cdcfedata_compressed_bytes: 206.94 MiB
/spanspan stylecolor:#9cdcfeprimary_key_bytes_in_memory: 96.93 KiB
/spanspan stylecolor:#9cdcfemarks: 1083
/spanspan stylecolor:#9cdcfebytes_on_disk: 207.07 MiB
/spanspan stylecolor:#9cdcfe1 rows in set. Elapsed: 0.003 sec.
/span/code/span/span/span 客户端输出表明
表数据以wide format存储在一个特定目录每个列有一个数据文件和mark文件。表有887万行数据。未压缩的数据有733.28 MB。压缩之后的数据有206.94 MB。有1083个主键索引条目大小是96.93 KB。在磁盘上表的数据、标记文件和主索引文件总共占用207.07 MB。
五、针对海量数据规模的索引设计
在传统的关系数据库管理系统中每个表行包含一个主索引。对于我们的数据集这将导致主索引——通常是一个B()-Tree的数据结构——包含887万个条目。 这样的索引允许快速定位特定的行从而提高查找点查和更新的效率。在B()-Tree数据结构中搜索一个条目的平均时间复杂度为O(log2n)。对于一个有887万行的表这意味着需要23步来定位任何索引条目。 这种能力是有代价的:额外的磁盘和内存开销以及向表中添加新行和向索引中添加条目时更高的插入成本(有时还需要重新平衡B-Tree)。 考虑到与B-Tee索引相关的挑战ClickHouse中的表引擎使用了一种不同的方法。ClickHouseMergeTree Engine引擎系列被设计和优化用来处理大量数据。 这些表被设计为每秒接收数百万行插入并存储非常大(100 pb)的数据量。 数据被一批一批的快速写入表中并在后台应用合并规则。
在ClickHouse中每个数据部分data part都有自己的主索引。当他们被合并时合并部分的主索引也被合并。
在大规模中情况下磁盘和内存的效率是非常重要的。因此不是为每一行创建索引而是为一组数据行称为颗粒granule构建一个索引条目。
之所以可以使用这种稀疏索引是因为ClickHouse会按照主键列的顺序将一组行存储在磁盘上。
与直接定位单个行(如基于B-Tree的索引)不同稀疏主索引允许它快速(通过对索引项进行二分查找)识别可能匹配查询的行组。
然后潜在的匹配行组(颗粒)以并行的方式被加载到ClickHouse引擎中以便找到匹配的行。
这种索引设计允许主索引很小(它可以而且必须完全适合主内存)同时仍然显著加快查询执行时间特别是对于数据分析用例中常见的范围查询。
下面详细说明了ClickHouse是如何构建和使用其稀疏主索引的。在本文后面我们将讨论如何选择、移除和排序用于构建索引的表列(主键列)的一些最佳实践。 六、数据按照主键排序存储在磁盘上
上面创建的表有
联合主键 (UserID, URL)联合排序键 (UserID, URL, EventTime)。 note 如果我们只指定了排序键那么主键将隐式定义为排序键。 为了提高内存效率我们显式地指定了一个主键只包含查询过滤的列。基于主键的主索引被完全加载到主内存中。 为了上下文的一致性和最大的压缩比例我们单独定义了排序键排序键包含当前表所有的列和压缩算法有关一般排序之后又更好的压缩率。 如果同时指定了主键和排序键则主键必须是排序键的前缀。 插入的行按照主键列(以及排序键的附加EventTime列)的字典序(从小到大)存储在磁盘上。 note ClickHouse允许插入具有相同主键列的多行数据。在这种情况下(参见下图中的第1行和第2行)最终的顺序是由指定的排序键决定的这里是EventTime列的值。 如下图所示ClickHouse是列存数据库。
在磁盘上每个表都有一个数据文件(*.bin)该列的所有值都以压缩格式存储并且在这个例子中这887万行按主键列(以及附加的排序键列)的字典升序存储在磁盘上 UserID第一位然后是URL最后是EventTime UserID.binURL.bin和EventTime.bin是UserIDURL和EventTime列的数据文件。 note 因为主键定义了磁盘上行的字典顺序所以一个表只能有一个主键。 我们从0开始对行进行编号以便与ClickHouse内部行编号方案对齐该方案也用于记录消息。 七、数据被组织成颗粒以进行并行数据处理
出于数据处理的目的表的列值在逻辑上被划分为多个颗粒。颗粒是流进ClickHouse进行数据处理的最小的不可分割数据集。这意味着ClickHouse不是读取单独的行而是始终读取(以流方式并并行地)整个行组颗粒。 note 列值并不物理地存储在颗粒中颗粒只是用于查询处理的列值的逻辑组织方式。 下图显示了如何将表中的887万行(列值)组织成1083个颗粒这是表的DDL语句包含设置index_granularity(设置为默认值8192)的结果。 第一个(根据磁盘上的物理顺序)8192行(它们的列值)在逻辑上属于颗粒0然后下一个8192行(它们的列值)属于颗粒1以此类推。 note 最后一个颗粒1082颗粒是少于8192行的。 我们在本指南开头的“DDL 语句详细信息”中提到我们禁用了自适应索引粒度为了简化本指南中的讨论并使图表和结果可重现。 因此示例表中所有颗粒除了最后一个都具有相同大小。 对于具有自适应索引粒度的表默认情况下索引粒度是自适应的某些粒度的大小可以小于 8192 行具体取决于行数据大小。 我们将主键列(UserID, URL)中的一些列值标记为橙色。 这些橙色标记的列值是每个颗粒中第一行的主键列值。正如我们将在下面看到的这些橙色标记的列值将是表主索引中的条目。 我们从0开始对行进行编号以便与ClickHouse内部行编号方案对齐该方案也用于记录消息。 八、每个颗粒对应主索引的一个条目
主索引是基于上图中显示的颗粒创建的。这个索引是一个未压缩的扁平数组文件(primary.idx)包含从0开始的所谓的数字索引标记。
下面的图显示了索引存储了每个颗粒的最小主键列值(在上面的图中用橙色标记的值)。 例如
第一个索引条目(下图中的“mark 0”)存储上图中颗粒0的主键列的最小值第二个索引条目(下图中的“mark 1”)存储上图中颗粒1的主键列的最小值以此类推。 在我们的表中索引总共有1083个条目887万行数据和1083个颗粒: note 最后一个索引条目(上图中的“mark 1082”)存储了上图中颗粒1082的主键列的最大值。 索引条目(索引标记)不是基于表中的特定行而是基于颗粒。例如对于上图中的索引条目‘mark 0’在我们的表中没有UserID为240.923且URL为“goal://metry10000467796a411…”的行相反对于该表有一个颗粒0在该颗粒中最小UserID值是240.923最小URL值是“goal://metry10000467796a411…”这两个值来自不同的行。 主索引文件完全加载到主内存中。如果文件大于可用的空闲内存空间则ClickHouse将发生错误。 主键条目称为索引标记因为每个索引条目都标志着特定数据范围的开始。对于示例表: UserID index marks: 主索引中存储的UserID值按升序排序。 上图中的‘mark 1’指示颗粒1中所有表行的UserID值以及随后所有颗粒中的UserID值都保证大于或等于4.073.710。 正如我们稍后将看到的, 当查询对主键的第一列进行过滤时此全局有序使ClickHouse能够对第一个键列的索引标记使用二分查找算法。 URL index marks: 主键列UserID和URL有相同的基数这意味着第一列之后的所有主键列的索引标记通常只表示每个颗粒的数据范围。 例如‘mark 0’中的URL列所有的值都大于等于goal://metry10000467796a411... 然后颗粒1中的URL并不是如此这是因为‘mark 1‘与‘mark 0‘具有不同的UserID列值。 稍后我们将更详细地讨论这对查询执行性能的影响。
九、主索引被用来选择颗粒
现在我们可以在主索引的支持下执行查询。
下面计算UserID 749927693点击次数最多的10个url。 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span URLspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span UserID span stylecolor:#d4d4d4/span span stylecolor:#b5cea8749927693/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─URL────────────────────────────┬─Count─┐
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-barana.. │ 170 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-id371...│ 52 │
/spanspan stylecolor:#9cdcfe│ http://public_search │ 45 │
/spanspan stylecolor:#9cdcfe│ http://kovrik-medvedevushku-...│ 36 │
/spanspan stylecolor:#9cdcfe│ http://forumal │ 33 │
/spanspan stylecolor:#9cdcfe│ http://korablitz.ru/L_1OFFER...│ 14 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-id371...│ 14 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-john-D...│ 13 │
/spanspan stylecolor:#9cdcfe│ http://auto.ru/chatay-john-D...│ 10 │
/spanspan stylecolor:#9cdcfe│ http://wot/html?page/23600_m...│ 9 │
/spanspan stylecolor:#9cdcfe└────────────────────────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.005 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 8.19 thousand rows,
/span/spanspan stylecolor:#9cdcfe740.18 KB (1.53 million rows/s., 138.59 MB/s.)
/span/code/span/span/span ClickHouse客户端的输出显示没有进行全表扫描只有8.19千行流到ClickHouse。
如果trace logging打开了那ClickHouse服务端日志会显示ClickHouse正在对1083个UserID索引标记执行二分查找以便识别可能包含UserID列值为749927693的行的颗粒。这需要19个步骤平均时间复杂度为O(log2 n) span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe...Executor): Key condition: (column 0 in [749927693, 749927693])
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Running binary search on index range for part all_1_9_2 (1083 marks)
/span/spanspan stylecolor:#9cdcfe...Executor): Found (LEFT) boundary mark: 176
/spanspan stylecolor:#9cdcfe...Executor): Found (RIGHT) boundary mark: 177
/spanspan stylecolor:#9cdcfe...Executor): Found continuous range in 19 steps
/spanspan stylecolor:#9cdcfe...Executor): Selected 1/1 parts by partition key, 1 parts by primary key,
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe 1/1083 marks by primary key, 1 marks to read from 1 ranges
/span/spanspan stylecolor:#9cdcfe...Reading ...approx. 8192 rows starting from 1441792
/span/code/span/span/span 我们可以在上面的跟踪日志中看到1083个现有标记中有一个满足查询。Trace Log详情
我们也可以通过使用EXPLAIN来重现这个结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6EXPLAIN/span indexes span stylecolor:#d4d4d4/span span stylecolor:#b5cea81/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span URLspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span UserID span stylecolor:#d4d4d4/span span stylecolor:#b5cea8749927693/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果如下 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─explain───────────────────────────────────────────────────────────────────────────────┐
/spanspan stylecolor:#9cdcfe│ Expression (Projection) │
/spanspan stylecolor:#9cdcfe│ Limit (preliminary LIMIT (without OFFSET)) │
/spanspan stylecolor:#9cdcfe│ Sorting (Sorting for ORDER BY) │
/spanspan stylecolor:#9cdcfe│ Expression (Before ORDER BY) │
/spanspan stylecolor:#9cdcfe│ Aggregating │
/spanspan stylecolor:#9cdcfe│ Expression (Before GROUP BY) │
/spanspan stylecolor:#9cdcfe│ Filter (WHERE) │
/spanspan stylecolor:#9cdcfe│ SettingQuotaAndLimits (Set limits and quota after reading from storage) │
/spanspan stylecolor:#9cdcfe│ ReadFromMergeTree │
/spanspan stylecolor:#9cdcfe│ Indexes: │
/spanspan stylecolor:#9cdcfe│ PrimaryKey │
/spanspan stylecolor:#9cdcfe│ Keys: │
/spanspan stylecolor:#9cdcfe│ UserID │
/spanspan stylecolor:#9cdcfe│ Condition: (UserID in [749927693, 749927693]) │
/spanspan stylecolor:#9cdcfe│ Parts: 1/1 │
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe│ Granules: 1/1083 │
/span/spanspan stylecolor:#9cdcfe└───────────────────────────────────────────────────────────────────────────────────────┘
/span
span stylecolor:#9cdcfe16 rows in set. Elapsed: 0.003 sec.
/span/code/span/span/span 客户端输出显示在1083个颗粒中选择了一个可能包含UserID列值为749927693的行。 Conclusion 当查询对联合主键的一部分并且是第一个主键进行过滤时ClickHouse将主键索引标记运行二分查找算法。 正如上面所讨论的ClickHouse使用它的稀疏主索引来快速(通过二分查找算法)选择可能包含匹配查询的行的颗粒。
这是ClickHouse查询执行的第一阶段(颗粒选择)。
在第二阶段(数据读取中), ClickHouse定位所选的颗粒以便将它们的所有行流到ClickHouse引擎中以便找到实际匹配查询的行。
我们将在下一节更详细地讨论第二阶段。 十、标记文件用来定位颗粒
下图描述了上表主索引文件的一部分。 如上所述通过对索引的1083个UserID标记进行二分搜索确定了第176个标记。因此它对应的颗粒176可能包含UserID列值为749.927.693的行。
颗粒选择的具体过程
为了确认(或排除)颗粒176中的某些行包含UserID列值为749.927.693需要将属于此颗粒的所有8192行读取到ClickHouse。
为了读取这部分数据ClickHouse需要知道颗粒176的物理地址。
在ClickHouse中我们表的所有颗粒的物理位置都存储在标记文件中。与数据文件类似每个表的列有一个标记文件。
下图显示了三个标记文件UserID.mrk、URL.mrk、EventTime.mrk为表的UserID、URL和EventTime列存储颗粒的物理位置。 我们已经讨论了主索引是一个扁平的未压缩数组文件(primary.idx)其中包含从0开始编号的索引标记。
类似地标记文件也是一个扁平的未压缩数组文件(*.mrk)其中包含从0开始编号的标记。
一旦ClickHouse确定并选择了可能包含查询所需的匹配行的颗粒的索引标记就可以在标记文件数组中查找以获得颗粒的物理位置。
每个特定列的标记文件条目以偏移量的形式存储两个位置: 第一个偏移量(上图中的block_offset)是在包含所选颗粒的压缩版本的压缩列数据文件中定位块。这个压缩块可能包含几个压缩的颗粒。所定位的压缩文件块在读取时被解压到内存中。 标记文件的第二个偏移量(上图中的“granule_offset”)提供了颗粒在解压数据块中的位置。
定位到的颗粒中的所有8192行数据都会被ClickHouse加载然后进一步处理。 为什么需要mark文件 为什么主索引不直接包含与索引标记相对应的颗粒的物理位置 因为ClickHouse设计的场景就是超大规模数据非常高效地使用磁盘和内存非常重要。 主索引文件需要放入内存中。 对于我们的示例查询ClickHouse使用了主索引并选择了可能包含与查询匹配的行的单个颗粒。只有对于这一个颗粒ClickHouse才需定位物理位置以便将相应的行组读取以进一步的处理。 而且只有UserID和URL列需要这个偏移量信息。 对于查询中不使用的列例如EventTime不需要偏移量信息。 对于我们的示例查询Clickhouse只需要UserID数据文件(UserID.bin)中176颗粒的两个物理位置偏移以及URL数据文件(URL.data)中176颗粒的两个物理位置偏移。 由mark文件提供的间接方法避免了直接在主索引中存储所有三个列的所有1083个颗粒的物理位置的条目因此避免了在主内存中有不必要的(可能未使用的)数据。 下面的图表和文本说明了我们的查询示例ClickHouse如何在UserID.bin数据文件中定位176颗粒。 我们在本文前面讨论过ClickHouse选择了主索引标记176因此176颗粒可能包含查询所需的匹配行。
ClickHouse现在使用从索引中选择的标记号(176)在UserID.mark中进行位置数组查找以获得两个偏移量用于定位颗粒176。
如图所示第一个偏移量是定位UserID.bin数据文件中的压缩文件块该数据文件包含颗粒176的压缩数据。
一旦所定位的文件块被解压缩到主内存中就可以使用标记文件的第二个偏移量在未压缩的数据中定位颗粒176。
ClickHouse需要从UserID.bin数据文件和URL.bin数据文件中定位(读取)颗粒176以便执行我们的示例查询(UserID为749.927.693的互联网用户点击次数最多的10个url)。
上图显示了ClickHouse如何定位UserID.bin数据文件的颗粒。
同时ClickHouse对URL.bin数据文件的颗粒176执行相同的操作。这两个不同的颗粒被对齐并加载到ClickHouse引擎以进行进一步的处理即聚合并计算UserID为749.927.693的所有行的每组URL值最后以计数降序输出10个最大的URL组。 十一、查询使用第二位主键的性能问题
当查询对复合键的一部分并且是第一个主键列进行过滤时ClickHouse将对主键列的索引标记运行二分查找。
但是当查询对联合主键的一部分但不是第一个键列进行过滤时会发生什么情况 note 我们讨论了这样一种场景:查询不是显式地对第一个主键列进行过滤而是对第一个主键列之后的任何键列进行过滤。 当查询同时对第一个主键列和第一个主键列之后的任何键列进行过滤时ClickHouse将对第一个主键列的索引标记运行二分查找。 我们使用一个查询来计算最点击http://public_search的最多的前10名用户 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span UserIDspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4/span span stylecolor:#ce9178http://public_search/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果是 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─────UserID─┬─Count─┐
/spanspan stylecolor:#9cdcfe│ 2459550954 │ 3741 │
/spanspan stylecolor:#9cdcfe│ 1084649151 │ 2484 │
/spanspan stylecolor:#9cdcfe│ 723361875 │ 729 │
/spanspan stylecolor:#9cdcfe│ 3087145896 │ 695 │
/spanspan stylecolor:#9cdcfe│ 2754931092 │ 672 │
/spanspan stylecolor:#9cdcfe│ 1509037307 │ 582 │
/spanspan stylecolor:#9cdcfe│ 3085460200 │ 573 │
/spanspan stylecolor:#9cdcfe│ 2454360090 │ 556 │
/spanspan stylecolor:#9cdcfe│ 3884990840 │ 539 │
/spanspan stylecolor:#9cdcfe│ 765730816 │ 536 │
/spanspan stylecolor:#9cdcfe└────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.086 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 8.81 million rows,
/span/spanspan stylecolor:#9cdcfe799.69 MB (102.11 million rows/s., 9.27 GB/s.)
/span/code/span/span/span 客户端输出表明尽管URL列是联合主键的一部分ClickHouse几乎执行了一一次全表扫描ClickHouse从表的887万行中读取881万行。
如果启用了trace日志那么ClickHouse服务日志文件显示ClickHouse在1083个URL索引标记上使用了通用的排除搜索以便识别那些可能包含URL列值为http://public_search的行。 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe...Executor): Key condition: (column 1 in [http://public_search,
/spanspan stylecolor:#9cdcfe http://public_search])
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Used generic exclusion search over index for part all_1_9_2
/span/spanspan stylecolor:#9cdcfe with 1537 steps
/spanspan stylecolor:#9cdcfe...Executor): Selected 1/1 parts by partition key, 1 parts by primary key,
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe 1076/1083 marks by primary key, 1076 marks to read from 5 ranges
/span/spanspan stylecolor:#9cdcfe...Executor): Reading approx. 8814592 rows with 10 streams
/span/code/span/span/span 我们可以在上面的跟踪日志示例中看到1083个颗粒中有1076个(通过标记)被选中因为可能包含具有匹配URL值的行。
这将导致881万行被读取到ClickHouse引擎中(通过使用10个流并行地读取)以便识别实际包含URL值http://public_search的行。
然而稍后仅仅39个颗粒包含匹配的行。
虽然基于联合主键(UserID, URL)的主索引对于加快过滤具有特定UserID值的行的查询非常有用但对于过滤具有特定URL值的行的查询索引并没有提供显著的帮助。
原因是URL列不是第一个主键列因此ClickHouse是使用一个通用的排除搜索算法(而不是二分查找)查找URL列的索引标志和UserID主键列不同它的算法的有效性依赖于URL列的基数。
为了说明我们给出通用的排除搜索算法的工作原理
通用排除搜索算法 下面将演示当通过第一个列之后的任何列选择颗粒时当前一个键列具有或高或低的基数时ClickHouse通用排除搜索算法 是如何工作的。 作为这两种情况的例子我们将假设 搜索URL值为W3的行。点击表抽象简化为只有简单值的UserID和UserID。相同联合主键(UserID、URL)。这意味着行首先按UserID值排序具有相同UserID值的行然后再按URL排序。颗粒大小为2即每个颗粒包含两行。 在下面的图表中我们用橙色标注了每个颗粒的最小键列值。 前缀主键低基数 假设UserID具有较低的基数。在这种情况下相同的UserID值很可能分布在多个表行和颗粒上从而分布在索引标记上。对于具有相同UserID的索引标记索引标记的URL值按升序排序(因为表行首先按UserID排序然后按URL排序)。这使得有效的过滤如下所述 在上图中我们的抽象样本数据的颗粒选择过程有三种不同的场景: 如果索引标记0的(最小)URL值小于W3并且紧接索引标记的URL值也小于W3则可以排除索引标记0因为标记0、标记1和标记2具有相同的UserID值。注意这个排除前提条件确保颗粒0和下一个颗粒1完全由U1 UserID值组成这样ClickHouse就可以假设颗粒0中的最大URL值也小于W3并排除该颗粒。 如果索引标记1的URL值小于(或等于)W3并且后续索引标记的URL值大于(或等于)W3则选择索引标记1因为这意味着粒度1可能包含URL为W3的行)。 可以排除URL值大于W3的索引标记2和3因为主索引的索引标记存储了每个颗粒的最小键列值因此颗粒2和3不可能包含URL值W3。 前缀主键高基数 当UserID具有较高的基数时相同的UserID值不太可能分布在多个表行和颗粒上。这意味着索引标记的URL值不是单调递增的 正如在上面的图表中所看到的所有URL值小于W3的标记都被选中以便将其关联的颗粒的行加载到ClickHouse引擎中。 这是因为虽然图中的所有索引标记都属于上面描述的场景1但它们不满足前面提到的排除前提条件即两个直接随后的索引标记都具有与当前标记相同的UserID值因此不能被排除。 例如考虑索引标记0其URL值小于W3并且其直接后续索引标记的URL值也小于W3。这不能排除因为两个直接随后的索引标记1和2与当前标记0没有相同的UserID值。 请注意随后的两个索引标记需要具有相同的UserID值。这确保了当前和下一个标记的颗粒完全由U1 UserID值组成。如果仅仅是下一个标记具有相同的UserID那么下一个标记的URL值可能来自具有不同UserID的表行——当您查看上面的图表时确实是这样的情况即W2来自U2而不是U1的行。 这最终阻止了ClickHouse对颗粒0中的最大URL值进行假设。相反它必须假设颗粒0可能包含URL值为W3的行并被迫选择标记0。 同样的情况也适用于标记1、2和3。 结论 当查询对联合主键的一部分列(但不是第一个键列)进行过滤时ClickHouse使用的通用排除搜索算法(而不是二分查找)在前一个键列基数较低时最有效。 在我们的示例数据集中两个键列(UserID、URL)都具有类似的高基数并且如前所述当URL列的前一个键列具有较高基数时通用排除搜索算法不是很有效。 看下跳数索引 因为UserID和URL具有较高的基数根据URL过滤数据不是特别有效对URL列创建二级跳数索引同样也不会有太多改善。 例如这两个语句在我们的表的URL列上创建并填充一个minmax跳数索引。 span stylecolor:#161517span stylebackground-color:var(--ifm-alert-background-color)span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6ALTER/span span stylecolor:#569cd6TABLE/span hits_UserID_URL span stylecolor:#569cd6ADD/span span stylecolor:#569cd6INDEX/span url_skipping_index URL span stylecolor:#569cd6TYPE/span minmax GRANULARITY span stylecolor:#b5cea84/spanspan stylecolor:#d4d4d4;/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ALTER/span span stylecolor:#569cd6TABLE/span hits_UserID_URL MATERIALIZE span stylecolor:#569cd6INDEX/span url_skipping_indexspan stylecolor:#d4d4d4;/span
/span/code/span/span/span/span/span ClickHouse现在创建了一个额外的索引来存储—每组4个连续的颗粒(注意上面ALTER TABLE语句中的GRANULARITY 4子句)—最小和最大的URL值 第一个索引条目(上图中的mark 0)存储属于表的前4个颗粒的行的最小和最大URL值。 第二个索引条目(mark 1)存储属于表中下一个4个颗粒的行的最小和最大URL值依此类推。 (ClickHouse还为跳数索引创建了一个特殊的标记文件用于定位与索引标记相关联的颗粒组。) 由于UserID和URL的基数相似在执行对URL的查询过滤时这个二级跳数索引不能帮助排除选择的颗粒。 正在寻找的特定URL值(http://public_search)很可能是索引为每组颗粒存储的最小值和最大值之间的值导致ClickHouse被迫选择这组颗粒(因为它们可能包含匹配查询的行)。 因此如果我们想显著提高过滤具有特定URL的行的示例查询的速度那么我们需要使用针对该查询优化的主索引。
此外如果我们想保持过滤具有特定UserID的行的示例查询的良好性能那么我们需要使用多个主索引。
下面是实现这一目标的方法。 十二、使用多个主键索引进行调优
如果我们想显著加快我们的两个示例查询——一个过滤具有特定UserID的行一个过滤具有特定URL的行——那么我们需要使用多个主索引通过使用这三个方法中的一个
新建一个不同主键的新表。创建一个物化视图。增加projection。
这三个方法都会有效地将示例数据复制到另一个表中以便重新组织表的主索引和行排序顺序。
然而这三个选项的不同之处在于附加表对于查询和插入语句的路由对用户的透明程度。
当创建有不同主键的第二个表时查询必须显式地发送给最适合查询的表版本并且必须显式地插入新数据到两个表中以保持表的同步 在物化视图中额外的表被隐藏数据自动在两个表之间保持同步 projection方式是最透明的选项因为除了自动保持隐藏的附加表与数据变化同步外ClickHouse还会自动选择最有效的表版本进行查询 下面我们使用真实的例子详细讨论下这三种方式。 十三、通过辅助表使用联合主键索引
我们创建一个新的附加表其中我们在主键中切换键列的顺序(与原始表相比) span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span span stylecolor:#569cd6TABLE/span hits_URL_UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanUserIDspan stylecolor:#d4d4d4/span UInt32span stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanURLspan stylecolor:#d4d4d4/span Stringspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanEventTimespan stylecolor:#d4d4d4/span span stylecolor:#569cd6DateTime/span
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTree
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4)/span
/span/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4,/span EventTimespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfeSETTINGS index_granularity span stylecolor:#d4d4d4/span span stylecolor:#b5cea88192/spanspan stylecolor:#d4d4d4,/span index_granularity_bytes span stylecolor:#d4d4d4/span span stylecolor:#b5cea80/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 写入887万行源表数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6INSERT/span span stylecolor:#569cd6INTO/span hits_URL_UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span span stylecolor:#d4d4d4*/span span stylecolor:#569cd6from/span hits_UserID_URLspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfeOk.
/span
span stylecolor:#9cdcfe0 rows in set. Elapsed: 2.898 sec. Processed 8.87 million rows, 838.84 MB (3.06 million rows/s., 289.46 MB/s.)
/span/code/span/span/span 最后optimize下 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6OPTIMIZE/span span stylecolor:#569cd6TABLE/span hits_URL_UserID FINALspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 因为我们切换了主键中列的顺序插入的行现在以不同的字典顺序存储在磁盘上(与我们的原始表相比)因此该表的1083个颗粒也包含了与以前不同的值 主键索引如下 现在计算最频繁点击URLhttp://public_search的前10名用户这时候的查询速度是明显加快的 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span UserIDspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_URL_UserID
/span/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4/span span stylecolor:#ce9178http://public_search/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─────UserID─┬─Count─┐
/spanspan stylecolor:#9cdcfe│ 2459550954 │ 3741 │
/spanspan stylecolor:#9cdcfe│ 1084649151 │ 2484 │
/spanspan stylecolor:#9cdcfe│ 723361875 │ 729 │
/spanspan stylecolor:#9cdcfe│ 3087145896 │ 695 │
/spanspan stylecolor:#9cdcfe│ 2754931092 │ 672 │
/spanspan stylecolor:#9cdcfe│ 1509037307 │ 582 │
/spanspan stylecolor:#9cdcfe│ 3085460200 │ 573 │
/spanspan stylecolor:#9cdcfe│ 2454360090 │ 556 │
/spanspan stylecolor:#9cdcfe│ 3884990840 │ 539 │
/spanspan stylecolor:#9cdcfe│ 765730816 │ 536 │
/spanspan stylecolor:#9cdcfe└────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.017 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 319.49 thousand rows,
/span/spanspan stylecolor:#9cdcfe11.38 MB (18.41 million rows/s., 655.75 MB/s.)
/span/code/span/span/span 现在没有全表扫描了ClickHouse执行高效了很多。
对于原始表中的主索引(其中UserID是第一个键列URL是第二个键列)ClickHouse在索引标记上使用了通用排除搜索来执行该查询但这不是很有效因为UserID和URL的基数同样很高。
将URL作为主索引的第一列ClickHouse现在对索引标记运行二分搜索。ClickHouse服务器日志文件中对应的跟踪日志 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe...Executor): Key condition: (column 0 in [http://public_search,
/spanspan stylecolor:#9cdcfe http://public_search])
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Running binary search on index range for part all_1_9_2 (1083 marks)
/span/spanspan stylecolor:#9cdcfe...Executor): Found (LEFT) boundary mark: 644
/spanspan stylecolor:#9cdcfe...Executor): Found (RIGHT) boundary mark: 683
/spanspan stylecolor:#9cdcfe...Executor): Found continuous range in 19 steps
/spanspan stylecolor:#9cdcfe...Executor): Selected 1/1 parts by partition key, 1 parts by primary key,
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe 39/1083 marks by primary key, 39 marks to read from 1 ranges
/span/spanspan stylecolor:#9cdcfe...Executor): Reading approx. 319488 rows with 2 streams
/span/code/span/span/span ClickHouse只选择了39个索引标记而不是使用通用排除搜索时的1076个。
请注意辅助表经过了优化以加快对url的示例查询过滤的执行。
像之前我们查询过滤URL一样如果我们现在对辅助表查询过滤UserID性能同样会比较差因为现在UserID是第二主索引键列所以ClickHouse将使用通用排除搜索算法查找颗粒这对于类似高基数的UserID和URL来说不是很有效。
点击下面了解详情
对UserID的查询过滤性能较差
现在我们有了两张表。优化了对UserID和URL的查询过滤分别: 十四、通过物化视图使用联合主键
在原表上创建物化视图 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span MATERIALIZED span stylecolor:#569cd6VIEW/span mv_hits_URL_UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTreespan stylecolor:#d4d4d4(/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4,/span EventTimespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfePOPULATE
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6AS/span span stylecolor:#569cd6SELECT/span span stylecolor:#d4d4d4*/span span stylecolor:#569cd6FROM/span hits_UserID_URLspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfeOk.
/span
span stylecolor:#9cdcfe0 rows in set. Elapsed: 2.935 sec. Processed 8.87 million rows, 838.84 MB (3.02 million rows/s., 285.84 MB/s.)
/span/code/span/span/span note 我们在视图的主键中切换键列的顺序(与原始表相比)物化视图由一个隐藏表支持该表的行顺序和主索引基于给定的主键定义我们使用POPULATE关键字以便用源表hits_UserID_URL中的所有887万行立即导入新的物化视图如果在源表hits_UserID_URL中插入了新行那么这些行也会自动插入到隐藏表中实际上隐式创建的隐藏表的行顺序和主索引与我们上面显式创建的辅助表相同: ClickHouse将隐藏表的列数据文件(.bin)、标记文件(.mrk2)和主索引(primary.idx)存储在ClickHouse服务器的数据目录的一个特殊文件夹中 物化视图背后的隐藏表(和它的主索引)现在可以用来显著加快我们在URL列上查询过滤的执行速度 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span UserIDspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span mv_hits_URL_UserID
/span/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4/span span stylecolor:#ce9178http://public_search/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─────UserID─┬─Count─┐
/spanspan stylecolor:#9cdcfe│ 2459550954 │ 3741 │
/spanspan stylecolor:#9cdcfe│ 1084649151 │ 2484 │
/spanspan stylecolor:#9cdcfe│ 723361875 │ 729 │
/spanspan stylecolor:#9cdcfe│ 3087145896 │ 695 │
/spanspan stylecolor:#9cdcfe│ 2754931092 │ 672 │
/spanspan stylecolor:#9cdcfe│ 1509037307 │ 582 │
/spanspan stylecolor:#9cdcfe│ 3085460200 │ 573 │
/spanspan stylecolor:#9cdcfe│ 2454360090 │ 556 │
/spanspan stylecolor:#9cdcfe│ 3884990840 │ 539 │
/spanspan stylecolor:#9cdcfe│ 765730816 │ 536 │
/spanspan stylecolor:#9cdcfe└────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.026 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 335.87 thousand rows,
/span/spanspan stylecolor:#9cdcfe13.54 MB (12.91 million rows/s., 520.38 MB/s.)
/span/code/span/span/span 物化视图背后隐藏表(及其主索引)实际上与我们显式创建的辅助表是相同的所以查询的执行方式与显式创建的表相同。
ClickHouse服务器日志文件中相应的跟踪日志确认了ClickHouse正在对索引标记运行二分搜索 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe...Executor): Key condition: (column 0 in [http://public_search,
/spanspan stylecolor:#9cdcfe http://public_search])
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Running binary search on index range ...
/span/spanspan stylecolor:#9cdcfe...
/spanspan stylecolor:#9cdcfe...Executor): Selected 4/4 parts by partition key, 4 parts by primary key,
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe 41/1083 marks by primary key, 41 marks to read from 4 ranges
/span/spanspan stylecolor:#9cdcfe...Executor): Reading approx. 335872 rows with 4 streams
/span/code/span/span/span 十五、通过projections使用联合主键索引
在原表上创建projection span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6ALTER/span span stylecolor:#569cd6TABLE/span hits_UserID_URL
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6ADD/span PROJECTION prj_url_userid
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6SELECT/span span stylecolor:#d4d4d4*/span
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 物化projection span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6ALTER/span span stylecolor:#569cd6TABLE/span hits_UserID_URL
/spanspan stylecolor:#9cdcfe MATERIALIZE PROJECTION prj_url_useridspan stylecolor:#d4d4d4;/span
/span/code/span/span/span note 该projection正在创建一个隐藏表该表的行顺序和主索引基于该projection的给定order BY子句SHOW TABLES 语句查询是不会列出这个隐藏表的我们使用MATERIALIZE关键字以便立即用源表hits_UserID_URL的所有887万行导入隐藏表如果在源表hits_UserID_URL中插入了新行那么这些行也会自动插入到隐藏表中查询总是(从语法上)针对源表hits_UserID_URL但是如果隐藏表的行顺序和主索引允许更有效地执行查询那么将使用该隐藏表请注意投影(projections)不会使 ORDER BY 查询语句的效率更高即使 ORDER BY 匹配上了 projection 的 ORDER BY 语句(请参阅https://github.com/ClickHouse/ClickHouse/issues/47333)实际上隐式创建的隐藏表的行顺序和主索引与我们显式创建的辅助表相同 ClickHouse将隐藏表的列数据文件(.bin)、标记文件(.mrk2)和主索引(primary.idx)存储在一个特殊的文件夹中(在下面的截图中用橙色标记)紧挨着源表的数据文件、标记文件和主索引文件 由投影创建的隐藏表(以及它的主索引)现在可以(隐式地)用于显著加快URL列上查询过滤的执行。注意查询在语法上针对投影的源表。 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span UserIDspan stylecolor:#d4d4d4,/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Count
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_UserID_URL
/span/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4/span span stylecolor:#ce9178http://public_search/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6GROUP/span span stylecolor:#569cd6BY/span UserID
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Count span stylecolor:#569cd6DESC/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6LIMIT/span span stylecolor:#b5cea810/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 结果 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─────UserID─┬─Count─┐
/spanspan stylecolor:#9cdcfe│ 2459550954 │ 3741 │
/spanspan stylecolor:#9cdcfe│ 1084649151 │ 2484 │
/spanspan stylecolor:#9cdcfe│ 723361875 │ 729 │
/spanspan stylecolor:#9cdcfe│ 3087145896 │ 695 │
/spanspan stylecolor:#9cdcfe│ 2754931092 │ 672 │
/spanspan stylecolor:#9cdcfe│ 1509037307 │ 582 │
/spanspan stylecolor:#9cdcfe│ 3085460200 │ 573 │
/spanspan stylecolor:#9cdcfe│ 2454360090 │ 556 │
/spanspan stylecolor:#9cdcfe│ 3884990840 │ 539 │
/spanspan stylecolor:#9cdcfe│ 765730816 │ 536 │
/spanspan stylecolor:#9cdcfe└────────────┴───────┘
/span
span stylecolor:#9cdcfe10 rows in set. Elapsed: 0.029 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 319.49 thousand rows, 1
/span/spanspan stylecolor:#9cdcfe1.38 MB (11.05 million rows/s., 393.58 MB/s.)
/span/code/span/span/span 因为由投影创建的隐藏表(及其主索引)实际上与我们显式创建的辅助表相同所以查询的执行方式与显式创建的表相同。
ClickHouse服务器日志文件中跟踪日志确认了ClickHouse正在对索引标记运行二分搜索 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe...Executor): Key condition: (column 0 in [http://public_search,
/spanspan stylecolor:#9cdcfe http://public_search])
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Running binary search on index range for part prj_url_userid (1083 marks)
/span/spanspan stylecolor:#9cdcfe...Executor): ...
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe...Executor): Choose complete Normal projection prj_url_userid
/span/spanspan stylecolor:#9cdcfe...Executor): projection required columns: URL, UserID
/spanspan stylecolor:#9cdcfe...Executor): Selected 1/1 parts by partition key, 1 parts by primary key,
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfe 39/1083 marks by primary key, 39 marks to read from 1 ranges
/span/spanspan stylecolor:#9cdcfe...Executor): Reading approx. 319488 rows with 2 streams
/span/code/span/span/span 十六、小结
带有联合主键(UserID, URL)的表的主索引对于加快UserID的查询过滤非常有用。但是尽管URL列是联合主键的一部分但该索引在加速URL查询过滤方面并没有提供显著的帮助。
反之亦然具有复合主键(URL, UserID)的表的主索引加快了URL上的查询过滤但没有为UserID上的查询过滤提供太多支持。
由于主键列UserID和URL的基数同样很高过滤第二个键列的查询不会因为第二个键列位于索引中而受益太多。
因此从主索引中删除第二个键列(从而减少索引的内存消耗)并使用多个主索引是有意义的。
但是如果复合主键中的键列在基数上有很大的差异那么查询按基数升序对主键列进行排序是有益的。
主键键列之间的基数差得越大主键中的列的顺序越重要。我们将在下一章节对此进行演示。
十七、高效地为键列排序 在复合主键中键列的顺序会对以下两方面产生重大影响
查询中过滤次关键字列的效率以及表数据文件的压缩率。
为了演示这一点我们将使用我们的网络流量样本数据集(web traffic sample data set)这个版本 其中每一行包含三列分别表示互联网用户(UserID 列对 URLURL列的访问是否被标记为僵尸流量IsRobot 列。 我们将使用一个包含上述所有三列的复合主键该主键可用于加快计算以下内容的典型网络分析查询速度 特定 URL 有多少百分比流量来自机器人或 我们对特定用户是否为僵尸用户有多大把握来自该用户的流量中有多大比例被认为是或不是僵尸流量 我们使用该查询来计算我们要用作复合主键中三个列的基数注意我们使用 URL 表函数 来即席查询 TSV 数据而无需创建本地表。在 clickhouse client中运行此查询 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe formatReadableQuantityspan stylecolor:#d4d4d4(/spanuniqspan stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span cardinality_URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableQuantityspan stylecolor:#d4d4d4(/spanuniqspan stylecolor:#d4d4d4(/spanUserIDspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span cardinality_UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableQuantityspan stylecolor:#d4d4d4(/spanuniqspan stylecolor:#d4d4d4(/spanIsRobotspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span cardinality_IsRobot
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe c11::UInt64 span stylecolor:#569cd6AS/span UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c15::String span stylecolor:#569cd6AS/span URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c20::UInt8 span stylecolor:#569cd6AS/span IsRobot
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6FROM/span urlspan stylecolor:#d4d4d4(/spanspan stylecolor:#ce9178https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4!/span span stylecolor:#ce9178/span
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/span/code/span/span/span 响应如下: span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─cardinality_URL─┬─cardinality_UserID─┬─cardinality_IsRobot─┐
/spanspan stylecolor:#9cdcfe│ 2.39 million │ 119.08 thousand │ 4.00 │
/spanspan stylecolor:#9cdcfe└─────────────────┴────────────────────┴─────────────────────┘
/span
span stylecolor:#9cdcfe1 row in set. Elapsed: 118.334 sec. Processed 8.87 million rows, 15.88 GB (74.99 thousand rows/s., 134.21 MB/s.)
/span/code/span/span/span 我们可以看到各列之间的基数尤其是 URL 列和 IsRobot 列之间存在着很大的差异因此在复合主键中这些列的顺序对于有效加快对这些列的查询过滤速度以及实现表中列数据文件的最佳压缩比都非常重要。
为了证明这一点我们为僵尸流量分析数据创建了两个版本的表
带有复合主键(URL、UserID、IsRobot)的表 hits_URL_UserID_IsRobot,其中的键列按基数降序排列使用复合主键(IsRobot, UserID, URL) 创建表 hits_IsRobot_UserID_URL其中的键列按基数升序排列
创建具有复合主键(URL、UserID、IsRobot)的表 hits_URL_UserID_IsRobot span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span span stylecolor:#569cd6TABLE/span hits_URL_UserID_IsRobot
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanUserIDspan stylecolor:#d4d4d4/span UInt32span stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanURLspan stylecolor:#d4d4d4/span Stringspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanIsRobotspan stylecolor:#d4d4d4/span UInt8
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTree
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span span stylecolor:#d4d4d4(/spanURLspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4,/span IsRobotspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4;/span
/span/span/code/span/span/span 然后填充887万行数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6INSERT/span span stylecolor:#569cd6INTO/span hits_URL_UserID_IsRobot span stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe intHash32span stylecolor:#d4d4d4(/spanc11::UInt64span stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c15 span stylecolor:#569cd6AS/span URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c20 span stylecolor:#569cd6AS/span IsRobot
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span urlspan stylecolor:#d4d4d4(/spanspan stylecolor:#ce9178https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4!/span span stylecolor:#ce9178/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 响应如下: span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe0 rows in set. Elapsed: 104.729 sec. Processed 8.87 million rows, 15.88 GB (84.73 thousand rows/s., 151.64 MB/s.)
/span/code/span/span/span 接下来创建带有复合主键 (IsRobot,UserID,URL)的表 hits_IsRobot_UserID_URL span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6CREATE/span span stylecolor:#569cd6TABLE/span hits_IsRobot_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4(/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanUserIDspan stylecolor:#d4d4d4/span UInt32span stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanURLspan stylecolor:#d4d4d4/span Stringspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#d4d4d4/spanIsRobotspan stylecolor:#d4d4d4/span UInt8
/spanspan stylecolor:#9cdcfespan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ENGINE/span span stylecolor:#d4d4d4/span MergeTree
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfespan stylecolor:#569cd6PRIMARY/span span stylecolor:#569cd6KEY/span span stylecolor:#d4d4d4(/spanIsRobotspan stylecolor:#d4d4d4,/span UserIDspan stylecolor:#d4d4d4,/span URLspan stylecolor:#d4d4d4)/spanspan stylecolor:#d4d4d4;/span
/span/span/code/span/span/span 并在其中填入与上一个表相同的 887 万行数据 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6INSERT/span span stylecolor:#569cd6INTO/span hits_IsRobot_UserID_URL span stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe intHash32span stylecolor:#d4d4d4(/spanc11::UInt64span stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span UserIDspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c15 span stylecolor:#569cd6AS/span URLspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe c20 span stylecolor:#569cd6AS/span IsRobot
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span urlspan stylecolor:#d4d4d4(/spanspan stylecolor:#ce9178https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span URL span stylecolor:#d4d4d4!/span span stylecolor:#ce9178/spanspan stylecolor:#d4d4d4;/span
/span/code/span/span/span 响应如下: span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe0 rows in set. Elapsed: 95.959 sec. Processed 8.87 million rows, 15.88 GB (92.48 thousand rows/s., 165.50 MB/s.)
/span/code/span/span/span 1、在次关键字列上高效过滤
当查询对至少一列进行过滤时该列是复合关键字的一部分并且是第一关键字列那么 ClickHouse 将在关键字列的索引标记上运行二分查找算法。 当查询仅过滤属于复合关键字的某一列但不是第一关键字列时ClickHouse 将在关键字列的索引标记上使用通用排除搜索算法。 对于第二种情况复合主键中关键列的排序对通用排除搜索算法的有效性很重要。
这是一个对表中的 UserID 列进行过滤的查询我们对该表的关键字列(URL、UserID、IsRobot)按基数进行了降序排序 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanspan stylecolor:#d4d4d4*/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_URL_UserID_IsRobot
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span UserID span stylecolor:#d4d4d4/span span stylecolor:#b5cea8112304/span
/span/code/span/span/span 响应如下: span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─count()─┐
/spanspan stylecolor:#9cdcfe│ 73 │
/spanspan stylecolor:#9cdcfe└─────────┘
/span
span stylecolor:#9cdcfe1 row in set. Elapsed: 0.026 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 7.92 million rows,
/span/spanspan stylecolor:#9cdcfe31.67 MB (306.90 million rows/s., 1.23 GB/s.)
/span/code/span/span/span 对关键字列(IsRobot, UserID, URL)按基数升序排列的表进行相同的查询 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span span stylecolor:#dcdcaacount/spanspan stylecolor:#d4d4d4(/spanspan stylecolor:#d4d4d4*/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span hits_IsRobot_UserID_URL
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span UserID span stylecolor:#d4d4d4/span span stylecolor:#b5cea8112304/span
/span/code/span/span/span 响应如下: span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─count()─┐
/spanspan stylecolor:#9cdcfe│ 73 │
/spanspan stylecolor:#9cdcfe└─────────┘
/span
span stylecolor:#9cdcfe1 row in set. Elapsed: 0.003 sec.
/spanspan stylebackground-color:var(--docusaurus-highlighted-code-line-bg)span stylecolor:#9cdcfeProcessed 20.32 thousand rows,
/span/spanspan stylecolor:#9cdcfe81.28 KB (6.61 million rows/s., 26.44 MB/s.)
/span/code/span/span/span 我们可以看到在对关键列按基数进行升序排列的表中查询执行的效率和速度明显更高。 其原因是当通过具有较低基数前键列的次关键字列选择颗粒时 通用排除搜索算法最有效。 我们在本指南的上一节中对此进行了详细说明。 2、数据文件的最佳压缩率
此查询将比较上面创建的两个表中 UserID 列的压缩率 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:var(--ifm-pre-color)codespan stylecolor:#9cdcfespan stylecolor:#569cd6SELECT/span
/spanspan stylecolor:#9cdcfe span stylecolor:#569cd6table/span span stylecolor:#569cd6AS/span span stylecolor:#569cd6Table/spanspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe name span stylecolor:#569cd6AS/span span stylecolor:#569cd6Column/spanspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spandata_uncompressed_bytesspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Uncompressedspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe formatReadableSizespan stylecolor:#d4d4d4(/spandata_compressed_bytesspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Compressedspan stylecolor:#d4d4d4,/span
/spanspan stylecolor:#9cdcfe span stylecolor:#dcdcaaround/spanspan stylecolor:#d4d4d4(/spandata_uncompressed_bytes span stylecolor:#d4d4d4//span data_compressed_bytesspan stylecolor:#d4d4d4,/span span stylecolor:#b5cea80/spanspan stylecolor:#d4d4d4)/span span stylecolor:#569cd6AS/span Ratio
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6FROM/span systemspan stylecolor:#d4d4d4./spanspan stylecolor:#569cd6columns/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6WHERE/span span stylecolor:#d4d4d4(/spanspan stylecolor:#569cd6table/span span stylecolor:#d4d4d4/span span stylecolor:#ce9178hits_URL_UserID_IsRobot/span span stylecolor:#d4d4d4OR/span span stylecolor:#569cd6table/span span stylecolor:#d4d4d4/span span stylecolor:#ce9178hits_IsRobot_UserID_URL/spanspan stylecolor:#d4d4d4)/span span stylecolor:#d4d4d4AND/span span stylecolor:#d4d4d4(/spanname span stylecolor:#d4d4d4/span span stylecolor:#ce9178UserID/spanspan stylecolor:#d4d4d4)/span
/spanspan stylecolor:#9cdcfespan stylecolor:#569cd6ORDER/span span stylecolor:#569cd6BY/span Ratio span stylecolor:#569cd6ASC/span
/span/code/span/span/span 这是响应 span stylecolor:var(--prism-color)span stylebackground-color:var(--ifm-pre-background)span stylecolor:#dc143ccodespan stylecolor:#9cdcfe┌─Table───────────────────┬─Column─┬─Uncompressed─┬─Compressed─┬─Ratio─┐
/spanspan stylecolor:#9cdcfe│ hits_URL_UserID_IsRobot │ UserID │ 33.83 MiB │ 11.24 MiB │ 3 │
/spanspan stylecolor:#9cdcfe│ hits_IsRobot_UserID_URL │ UserID │ 33.83 MiB │ 877.47 KiB │ 39 │
/spanspan stylecolor:#9cdcfe└─────────────────────────┴────────┴──────────────┴────────────┴───────┘
/span
span stylecolor:#9cdcfe2 rows in set. Elapsed: 0.006 sec.
/span/code/span/span/span 我们可以看到在按关键字列(IsRobot、UserID、URL) 按基数升序排列的表中UserID 列的压缩率明显更高。
虽然两个表中存储的数据完全相同我们在两个表中插入了相同的 887 万行但复合主键中关键字列的顺序对表的 列数据文件中的 压缩数据所需的磁盘空间有很大影响
在具有复合主键(URL, UserID, IsRobot) 的表 hits_URL_UserID_IsRobot 中我们按照键列的基数降序排列此时 UserID.bin 数据文件占用11.24MB的磁盘空间。在具有复合主键(IsRobot, UserID, URL) 的表 hits_IsRobot_UserID_URL 中我们按照键列的基数升序排列UserID.bin 数据文件仅占用877.47 KiB的磁盘空间。
对磁盘上表的列数据进行良好的压缩比不仅能节省磁盘空间还能使需要从该列读取数据的查询尤其是分析查询更快因为将列数据从磁盘移动到主内存操作系统的文件缓存所需的 i/o 更少。
下面我们将说明为什么主键列按基数升序排列有利于提高表列的压缩率。
下图阐述了主键的磁盘上行顺序其中键列是按基数升序排列的 我们讨论过 表的行数据按主键列有序存储在磁盘上。
在上图中表格的行它们在磁盘上的列值首先按其 cl 值排序具有相同 cl 值的行按其 ch 值排序。由于第一键列 cl 的基数较低因此很可能存在具有相同 cl 值的行。因此ch值也很可能是有序的局部地--对于具有相同cl值的行而言。
如果在一列中相似的数据被放在彼此相近的位置例如通过排序那么这些数据将得到更好的压缩。 一般来说压缩算法会受益于数据的运行长度可见的数据越多压缩效果越好和局部性数据越相似压缩率越高。
与上图不同的是下图阐述了主键的磁盘上行顺序其中主键列是按基数降序排列的 现在表格的行首先按其 ch 值排序具有相同 ch 值的行按其 cl 值排序。 但是由于第一键列 ch 的基数很高因此不太可能存在具有相同 ch 值的行。因此cl值也不太可能是有序的局部地--对于具有相同ch值的行而言。
因此cl值很可能是随机排序的因此局部性和压缩比都很差。
小结
为了在查询中有效地过滤次关键字列和提高表列数据文件的压缩率按基数升序排列主键中的列是有益的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/84840.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!