news 2026/4/23 8:23:24

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/4/23 8:19:51

计算机Java毕设实战-基于java+springboot+vue的扶贫助农系统基于springboot的助农扶贫系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/23 8:21:12

亲测好用8个一键生成论文工具,研究生论文写作必备!

亲测好用8个一键生成论文工具&#xff0c;研究生论文写作必备&#xff01; AI 工具助力论文写作&#xff0c;效率提升不再是梦想 在研究生阶段&#xff0c;论文写作是每位学生都无法回避的重要任务。无论是开题报告、文献综述&#xff0c;还是最终的毕业论文&#xff0c;都需要…

作者头像 李华
网站建设 2026/4/12 8:18:13

RAG入门

对提取的文本进行分块def chunk_text(text, n, overlap):"""Chunks the given text into segments of n characters with overlap.Args:text (str): 文本n (int): 块长度overlap (int): 重叠度Returns:List[str]: A list of text chunks."""chun…

作者头像 李华
网站建设 2026/4/18 3:25:48

从对象结构到锁机制:Java 对象锁与类锁深度解析

从对象结构到锁机制&#xff1a;Java 对象锁与类锁深度解析 Java 的并发控制中&#xff0c;synchronized 是最经典的内置锁机制。它基于 JVM 的对象结构实现&#xff0c;分为对象锁&#xff08;实例锁&#xff09;和类锁&#xff08;静态锁&#xff09;。下面从对象内存布局入…

作者头像 李华
网站建设 2026/4/8 22:45:29

实战复盘:如何用 HTML+JS+AI 打造一款“影迹”智能影视管理系统

在数字化时代&#xff0c;我们囤积了大量的影视资源链接&#xff08;百度网盘、夸克网盘&#xff09;&#xff0c;但它们通常以杂乱的 TXT 文本形式存在。只有链接&#xff0c;没有海报&#xff1b;只有片名&#xff0c;没有评分。 为了解决这个痛点&#xff0c;我开发了**“影…

作者头像 李华