当前位置: 首页 > news >正文

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)等内容。

http://www.jsqmd.com/news/294420/

相关文章:

  • ClickHouse 高分笔记
  • 全国逛同一座城?我们都活在“复制粘贴”的模块化世界里
  • 【课程设计/毕业设计】基于springboot的助农扶贫系统家乡扶贫助农系统【附源码、数据库、万字文档】
  • 微信小程序 == rsa加解密工具
  • logging模块,scrapy全站爬取
  • CrawlSpider自动爬取,ImagePipeline
  • TPDO vs RPDO 对比总结
  • 贪吃蛇 set和deque使用
  • 亲测好用8个一键生成论文工具,研究生论文写作必备!
  • 电力企业数字化管理升级,如何实现项目、人员、财务一体化管控?
  • 轰炸敌人,最多可以摧毁的敌人城堡数目
  • 汉诺塔问题及其扩展
  • 揭秘天猫超市购物卡回收其中的猫腻
  • Spring Cloud Alibaba 2025.0.0 整合 ELK 实现日志 - 详解
  • 三分之一2-5天和三分之二6-13天资金利用率对比学习
  • Android关机
  • 221_尚硅谷_实现接口和继承比较(2)
  • 2026年苏州智能硬件设计公司推荐:飓风工业设计,企业产品设计/专业工业设计/产品外观设计/电子产品设计/工业设计/机械产品设计公司精选
  • 2026年国内知名的投影机品牌排名,激光投影仪/20000流明投影机出租/画展投影机出租/雾幕投影机,投影机公司排行
  • JAVA自学之路1.1:JAVA入门纠错
  • 2026软考高级系统架构师备考资料-录播+直播
  • 微信立减金回收攻略,方法、流程与折扣全解析
  • 安达发|精准排产,守护生命:医疗器械行业车间排产的数字化革命
  • 2026年市场评价好的纸盒品牌推荐排行,纸盒/彩印包装/农产品纸箱/工业纸盒/纸箱/工业纸箱,纸盒批发厂家推荐排行
  • Deepseek问答:开发人员如何选书
  • php开源短视频源码,JSON对象转化API
  • 短视频平台php源码,字符缓冲流的特有功能
  • 短视频app搭建,如何实现毛玻璃效果?
  • 小视频平台源码,ElementUI 本地分页
  • C 语言基础:输入输出、运算符与流程控制全梳理