news 2026/5/30 20:21:26

ClickHouse 原理:深入理解数据分片 Part 和分区 Partition

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse 原理:深入理解数据分片 Part 和分区 Partition

在 ClickHouse 中,磁盘上存储表数据一部分的物理文件被称为数据分片part。数据分区partition则是通过分区键创建表的数据逻辑划分。通过分区,用户可以更高效地存储、查询和操作数据的子集,从而提升大表的性能和可管理性。在本博客系列的第一篇中,我们将介绍 ClickHouse 中的数据分片 part 与分区 partition,以及它们的使用方式和区别。

1. Part

如前所述,Part是磁盘上的物理文件。默认情况下,所有与数据相关的文件都位于/var/lib/clickhouse目录下。ClickHouse 中的每个 MergeTree 表都有一个唯一目录路径来存储Part。你可以通过system.parts系统表查询到Part的实际存储位置、片段名称、分区信息(如果有的话)以及其他一些有用的信息。

下方展示了从system.parts表中查询结果的一个示例。其中,part_type字段中的Wide表示每列在文件系统中以单独的文件形式存储;而Compact则表示所有列都存储在同一个文件中。此外,在partition列中,tuple()表示该表未进行分区。

SELECTsubstr(table,1,22),partitionASprt,name,part_type,pathFROMsystem.partsWHEREdatabase='sampleDatasets'ORDERBYtableASC,partitionASC,nameASCQuery id:2a9462a8-7e74-4c0f-a89a-0bd2a31d0a46 ┌─substring(table,1,22)─┬─prt─────┬─name──────────┬─part_type─┬─path──────────────────────────────────────────────────────────────────────────────┐ │.inner_id.ca612a5e-5ee │ tuple()│ all_1_1_1 │ Compact │/var/lib/clickhouse/store/4c6/4c6dfe9a-b697-4f9a-928f-f829bf44fb5c/all_1_1_1/│ │ opensky │ tuple()│ all_1_1_1_5 │ Wide │/var/lib/clickhouse/store/1af/1afc664b-0a25-443a-a317-532532434753/all_1_1_1_5/│ │ opensky │ tuple()│ all_2_2_1_5 │ Wide │/var/lib/clickhouse/store/1af/1afc664b-0a25-443a-a317-532532434753/all_2_2_1_5/│ │ opensky │ tuple()│ all_3_3_0_5 │ Wide │/var/lib/clickhouse/store/1af/1afc664b-0a25-443a-a317-532532434753/all_3_3_0_5/│ │ opensky │ tuple()│ all_4_4_0_5 │ Compact │/var/lib/clickhouse/store/1af/1afc664b-0a25-443a-a317-532532434753/all_4_4_0_5/│ │ openskyDeletedRecord │ tuple()│ all_2_2_2 │ Compact │/var/lib/clickhouse/store/5b0/5b0e6758-ae46-4c25-9599-f2cddc362b5e/all_2_2_2/│ │ opensky_1000000 │ tuple()│ all_1_1_0 │ Wide │/var/lib/clickhouse/store/a2a/a2aa62d7-65bb-4bb2-bc5b-2c3d1befa147/all_1_1_0/│ │ opensky_freeze_restore │ tuple()│ all_1_1_1 │ Wide │/var/lib/clickhouse/store/2d0/2d0e6ad7-6fd4-408e-8c18-b39416ea8ff1/all_1_1_1/│ │ opensky_freeze_restore │ tuple()│ all_2_2_1 │ Wide │/var/lib/clickhouse/store/2d0/2d0e6ad7-6fd4-408e-8c18-b39416ea8ff1/all_2_2_1/│ │ opensky_freeze_restore │ tuple()│ all_3_3_0 │ Wide │/var/lib/clickhouse/store/2d0/2d0e6ad7-6fd4-408e-8c18-b39416ea8ff1/all_3_3_0/│ │ opensky_freeze_restore │ tuple()│ all_4_4_0 │ Compact │/var/lib/clickhouse/store/2d0/2d0e6ad7-6fd4-408e-8c18-b39416ea8ff1/all_4_4_0/│ │ opensky_redo_test │ tuple()│ all_1_2_1 │ Compact │/var/lib/clickhouse/store/e99/e99f1ab9-6d21-4d01-8f02-9f2aa0e6b45a/all_1_2_1/│ │ opensky_redo_test2 │ tuple()│ all_103_104_1 │ Compact │/var/lib/clickhouse/store/fac/facadfc3-1c5b-4775-bea7-53c262f7e237/all_103_104_1/│ │ test_table │ tuple()│ all_1_2_1 │ Compact │/var/lib/clickhouse/store/024/024a3a77-4ca9-4761-a2f1-4b36eb4ece0e/all_1_2_1/│ └─────────────────────────┴─────────┴───────────────┴───────────┴───────────────────────────────────────────────────────────────────────────────────┘

也可以在目录/var/lib/clickhouse/data/<DBNAME>/<TABLENAME>中查看表的数据分片Part,会发现该目录下存放都是符号链接,通过链接可以查看表包含的数据分片Part。比如,进入表mytest_of_ti所在目录查看:

root@clickhouse01:/var/lib/clickhouse/data/sampleDatasets/opensky# ls -al total 36 drwxr-x--- 7 clickhouse clickhouse 4096 Nov 21 10:00 . drwxr-x--- 3 clickhouse clickhouse 4096 Oct 16 13:13 .. drwxr-x--- 2 clickhouse clickhouse 4096 Nov 21 09:49 all_1_1_1_5 drwxr-x--- 2 clickhouse clickhouse 4096 Nov 21 09:49 all_2_2_1_5 drwxr-x--- 2 clickhouse clickhouse 4096 Nov 21 09:49 all_3_3_0_5 drwxr-x--- 2 clickhouse clickhouse 4096 Nov 21 09:49 all_4_4_0_5 drwxr-x--- 2 clickhouse clickhouse 4096 Nov 9 11:33 detached -rw-r----- 1 clickhouse clickhouse 1 Oct 16 13:13 format_version.txt -rw-r----- 1 clickhouse clickhouse 100 Nov 21 09:49 mutation_5.txt

如上例所示,sampleDatasets数据库中的opensky表包含 4 个数据分片Part。每个数据分片Part都有其独立的目录,且目录名称均以all_开头。以名为all_3_3_0_5的数据分片Part为例:

  • 第一个 3 表示数据分片Part所包含数据块的最小编号;
  • 第二个 3 表示数据分片Part所包含数据块的最大编号;
  • 0 表示合并层级(即数据分片Part由合并树的第几层生成);
  • 5 表示变更版本号(mutation version),用于标识数据分片Part是否经过了数据变更(mutation)操作。

此外,这些信息也可以通过system.parts系统表进行查询获取:

SELECTname,partition_id,min_block_number,max_block_number,level,data_versionFROMsystem.partsWHERE(database='sampleDatasets')AND(table='opensky')AND(name='all_3_3_0_5')Query id:0f2bb404-11a0-4df3-b1c1-7941698b9560 ┌─name────────┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┐ │ all_3_3_0_5 │all3305│ └─────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┘

2. Partitions

与数据分片Part一样,也可以从system.parts表中访问 MergeTree 表的分区信息。不过,在这里分区列不是用tuple()来表示了,而是具体的分区标识。要创建一个分区表,首先需要在创建表时使用PARTITION BY expr子句。例如,PARTITION BY toYYYMMDD(start_time)子句会根据start_time列按天创建分区。在下面的示例中可以看到,Partitions 分区名称和数据分片Part名称是不同的。此外,数据分片Part名称不再以all开头,而是以对应的分区标识作为前缀。分区是一种逻辑上的划分方式,而数据分片Part则是实际存储在磁盘上的物理文件。一个分区可以包含一个或多个数据分片Part

SELECTpartition,name,activeFROMsystem.partsWHERE(table='backups')AND(database='RECMAN')┌─partition─┬─name───────────┬─active─┐ │2022101720221017_1_1_0 │1│ │2022101820221018_2_2_0 │1│ │2022111420221114_3_3_0 │1│ └───────────┴────────────────┴────────┘

通常,分区用于提升查询性能,并为我们提供灵活管理数据子集的能力。你可以直接对分区进行查询、删除(DROP)、分离(DETACH)等操作。关于数据分片Part和分区Partitions的具体操作,我们将在后续的博客文章中详细讨论。

你可以通过在WHERE子句中指定条件,或使用隐藏列_partition_id来查询特定的分区。当然,更推荐使用官方支持的方式,即在WHERE子句中直接提供分区键的条件。但在某些场景下,我们也需要使用_partition_id

现在,让我们来看一个分区表的查询示例。假设我们的表recoDB.opensky_partitioned是按lastseen列进行分区的。我们既可以通过分区键列(即lastseen),也可以通过隐藏列_partition_id来访问特定的分区:

SELECTcount()FROMrecoDB.opensky_partitionedWHEREtoDate(lastseen)='2019-02-25'┌─count()─┐ │69480│ └─────────┘#####################################SELECTcount()FROMrecoDB.opensky_partitionedWHERE_partition_id='20190225'┌─count()─┐ │69480│ └─────────┘

此外,我们还可以利用_partition_id查询前 10 个分区的数据:

SELECT_partition_id,count()FROMrecoDB.opensky_partitionedGROUPBY_partition_idORDERBY2DESCLIMIT10┌─_partition_id─┬─count()─┐ │2019052490358│ │2019053187917│ │2019052387023│ │2019053086945│ │2019042585524│ │2019051685348│ │2019051585287│ │2019052285056│ │2019051784986│ │2019051084585│ └───────────────┴─────────┘

3. 结论

数据分片Part和分区Partitions是 ClickHouse 数据库的核心组成部分。一般来说,数据分片Part用于存储表中的一部分数据,是磁盘上的物理文件;而分区Partitions则是逻辑结构,常用于提升表的查询性能和数据管理效率。在本系列的第一篇文章中,我们介绍了 ClickHouse 中的数据分片Part与分区Partitions。在后续的文章中,我们将深入探讨对它们的操作、合并(merging)以及变更(mutations)等内容。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 13:11:33

三分之一2-5天和三分之二6-13天资金利用率对比学习

目录一、基础参数定义&#xff08;统一口径&#xff09;1. 基础仓位金额计算二、资金周转率与时间周期的数学建模1. 周期天数区间与均值2. 资金周转率定义&#xff08;单次交易&#xff09;3. 周转率差值与比例&#xff08;1&#xff09;周转率差值&#xff08;2&#xff09;周…

作者头像 李华
网站建设 2026/5/28 20:12:16

贪吃蛇 set和deque使用

#include <vector> #include <string> #include <deque> #include <set>using namespace std;// 您提供的 Node 结构体 typedef struct Node{int _x;int _y;Node(int x, int y){_x x;_y y;}// 重载 < 运算符&#xff0c;方便放入 set 中进行去重/…

作者头像 李华
网站建设 2026/5/28 13:11:36

AI大洪水来袭!90%的人还在卷算法,聪明的已经盯上“铁饭碗”——协调人

AI大洪水来袭!90%的人还在卷算法,聪明的已经盯上“铁饭碗”——协调人 目录 AI大洪水来袭!90%的人还在卷算法,聪明的已经盯上“铁饭碗”——协调人 🔴 淘汰预警:纯技术“工具人” 🔵 晋升密码:协调型“问题终结者” 我们应该怎么做 做 LLM 技术,这样转型 “技术 + 协…

作者头像 李华
网站建设 2026/5/28 20:18:41

Python如何识别周围WiFi:跨平台实现与进阶技巧

在物联网设备管理、网络安全审计或智能家居场景中&#xff0c;识别周围WiFi网络是基础需求。Python凭借其丰富的生态库&#xff0c;能够跨平台实现WiFi扫描、信号强度检测及网络分析。本文将系统梳理主流方法&#xff0c;结合代码示例与性能对比&#xff0c;帮助开发者快速构建…

作者头像 李华
网站建设 2026/5/28 13:11:39

基于spring mvc和mybatis的网上食品零食商城系统视频vue3

目录 系统架构与技术栈核心功能模块技术实现要点数据库设计示例部署与扩展建议 项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作 系统架构与技术栈 Spring MVC MyBatis 作为后端框架&#xff0c;Vue3 作为…

作者头像 李华