在 ClickHouse 中,磁碟上儲存表的部分資料的物理檔案稱為 "part"。"partition "是使用分割槽鍵建立的表資料的邏輯劃分。分割槽可用於提高大型表的效能和可管理性,允許使用者更有效地儲存、查詢和運算元據子集。
Parts
如前所述,"Parts"是磁碟上的物理檔案。預設情況下,所有資料相關檔案都位於"/var/lib/clickhouse"目錄下。ClickHouse 中的每個合併樹表都有唯一的儲存目錄路徑來儲存 Parts。你可以從 "system.parts "表中獲取parts的實際位置、parts名稱、分割槽資訊(如果有的話)以及其他一些有價值的資訊。
以下是從 system.parts 表查詢結果的示例。
SELECT substr(table, 1, 22), partition AS prt, name, part_type, path FROM system.parts WHERE database = 'mytest' ORDER BY table ASC, partition ASC, name ASC Query id: e2f55694-fa55-48f3-99f7-74bca59aca48 ┌─substring(table, 1, 22)─┬─prt──────┬─name─────────────────┬─part_type─┬─path──────────────────────────────────────────────────────────────────────────────────────┐ │ bucket_daily_stats_v2 │ tuple() │ all_1_1389_6_695 │ Wide │ /var/lib/clickhouse/store/7b0/7b0e6f30-114d-472d-8ff4-f4c9a4cf7cc1/all_1_1389_6_695/ │ │ corr_pair_value │ tuple() │ all_208611_209409_4 │ Wide │ /var/lib/clickhouse/store/5d7/5d732078-0f2e-4d04-9848-d216a1839b32/all_208611_209409_4/ │ │ corr_pair_value │ tuple() │ all_209410_209634_3 │ Wide │ /var/lib/clickhouse/store/5d7/5d732078-0f2e-4d04-9848-d216a1839b32/all_209410_209634_3/ │ │ corr_pair_value │ tuple() │ all_209635_210331_4 │ Wide │ /var/lib/clickhouse/store/5d7/5d732078-0f2e-4d04-9848-d216a1839b32/all_209635_210331_4/ │ │ mytest_of_ti │ 202408 │ 202408_4241_5001_5 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202408_4241_5001_5/ │ │ mytest_of_ti │ 202408 │ 202408_5002_5008_1 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202408_5002_5008_1/ │ │ mytest_of_ti │ 202408 │ 202408_5009_5045_2 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202408_5009_5045_2/ │ │ mytest_of_ti │ 202408 │ 202408_5046_5046_0 │ Compact │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202408_5046_5046_0/ │ │ mytest_of_ti │ 202409 │ 202409_5013_5624_5 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5013_5624_5/ │ │ mytest_of_ti │ 202409 │ 202409_5625_5661_2 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5625_5661_2/ │ │ mytest_of_ti │ 202409 │ 202409_5662_5699_2 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5662_5699_2/ │ │ mytest_of_ti │ 202409 │ 202409_5700_5708_1 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5700_5708_1/ │ │ mytest_of_ti │ 202409 │ 202409_5710_5793_4 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5710_5793_4/ │ │ mytest_of_ti │ 202409 │ 202409_5794_5794_0 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5794_5794_0/ │ │ mytest_of_ti │ 202409 │ 202409_5795_5795_0 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202409_5795_5795_0/ │ │ mytest_of_ti │ 202410 │ 202410_5703_5810_7 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5703_5810_7/ │ │ mytest_of_ti │ 202410 │ 202410_5811_5849_2 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5811_5849_2/ │ │ mytest_of_ti │ 202410 │ 202410_5850_5882_2 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5850_5882_2/ │ │ mytest_of_ti │ 202410 │ 202410_5883_5888_1 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5883_5888_1/ │ │ mytest_of_ti │ 202410 │ 202410_5889_5894_1 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5889_5894_1/ │ │ mytest_of_ti │ 202410 │ 202410_5895_5901_1 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5895_5901_1/ │ │ mytest_of_ti │ 202410 │ 202410_5902_5902_0 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5902_5902_0/ │ │ mytest_of_ti │ 202410 │ 202410_5903_5903_0 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5903_5903_0/ │ │ mytest_of_ti │ 202410 │ 202410_5904_5904_0 │ Wide │ /var/lib/clickhouse/store/32f/32ff94bb-43af-47c3-99b1-5c85e912483c/202410_5904_5904_0/ │ └─────────────────────────┴──────────┴──────────────────────┴───────────┴───────────────────────────────────────────────────────────────────────────────────────────┘
在 "part_type" 列中,"Wide "表示每一列都儲存在檔案系統中的一個單獨檔案中,而 "Compact "表示所有列都儲存在檔案系統的一個檔案中。此外,"partition "列中的 "tuple() "表示該表未分割槽。
也可以在目錄“/var/lib/clickhouse/data/<DBNAME>/<TABLENAME>”中檢視錶的 parts,會發現該目錄下存放都是符號連結,透過連結可以檢視錶包含的parts。比如,進入表 mytest_of_ti 所在目錄檢視:
# ls -la ...... drwxr-x--- 2 clickhouse clickhouse 4096 Oct 10 15:10 202410_5811_5849_2 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 11 15:10 202410_5850_5882_2 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 11 15:10 202410_5883_5888_1 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 11 15:10 202410_5889_5894_1 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 13 15:10 202410_5895_5901_1 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 13 15:10 202410_5902_5902_0 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 13 15:10 202410_5903_5903_0 drwxr-x--- 2 clickhouse clickhouse 4096 Oct 13 15:10 202410_5904_5904_0 drwxr-x--- 2 clickhouse clickhouse 10 Nov 11 2023 detached -rw-r----- 1 clickhouse clickhouse 1 Nov 11 2023 format_version.txt -rw-r----- 1 clickhouse clickhouse 123 Dec 11 2023 mutation_252.txt -rw-r----- 1 clickhouse clickhouse 96 Dec 11 2023 mutation_259.txt -rw-r----- 1 clickhouse clickhouse 230 Dec 11 2023 mutation_264.txt
可以統計出表mytest_of_ti一共有個part:
# ls -la |grep 20 |wc -l 133
以列出的202410_5850_5882_2 該part為例,其中202410表示分割槽id;5850表示part中最小的塊號;5882表示最大的塊號;2表示塊的級別(chunk level)。如果沒有做分割槽,part 的名稱以all_開頭。
也可以從系統表 system.parts 中檢視該part 的資訊:
SELECT name, partition_id, min_block_number, max_block_number, level, data_version FROM system.parts WHERE (database = 'factor_data') AND (table = 'factor_value_of_trading') AND (name = '202410_5850_5882_2') Query id: e6678b2e-31e2-4a9d-9c9b-16ff8bf9ecf0 ┌─name───────────────┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┐ │ 202410_5850_5882_2 │ 202410 │ 5850 │ 5882 │ 2 │ 5850 │ └────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┘ 1 row in set. Elapsed: 0.006 sec.
Partitions
與 parts 一樣,也可以從 “system.parts ”表中訪問合併樹表的分割槽資訊。不過,分割槽列現在不是用 “tuple() ”來表示了。要建立分割槽表,首先需要在建立表時使用 “PARTITION BY expr ”子句。例如,“PARTITION BY toYYYMMDD(start_time) ”子句建立了一個與 “start_time ”列相關的每日分割槽。在下面的示例中,可以看到Partitions名和parts名是不同的。分割槽類似於邏輯上的劃分,但 parts是作為物理檔案定位的。一個分割槽可以包含一個或多個 parts。
SELECT partition, name, active FROM system.parts WHERE (table = 'mytest_of_ti') AND (database = 'test') Query id: 9c8c15bc-df95-4713-b001-39447010a1ab ┌─partition─┬─name─────────────────┬─active─┐ │ 201411 │ 201411_1_1_1_264 │ 1 │ │ 201411 │ 201411_2_2_3_264 │ 1 │ │ 201412 │ 201412_3_3_3_264 │ 1 │ │ 201412 │ 201412_4_4_1_264 │ 1 │ │ 201412 │ 201412_5_5_1_264 │ 1 │ │ 202001 │ 202001_6_6_3_264 │ 1 │ │ 202002 │ 202002_7_7_3_264 │ 1 │ │ 202003 │ 202003_8_8_3_264 │ 1 │ │ 202004 │ 202004_9_9_1_264 │ 1 │ │ 202004 │ 202004_10_10_3_264 │ 1 │ ... │ 202410 │ 202410_5934_5934_0 │ 0 │ │ 202410 │ 202410_5935_5935_0 │ 0 │ │ 202410 │ 202410_5936_5936_0 │ 0 │ │ 202410 │ 202410_5937_5937_0 │ 1 │ │ 202410 │ 202410_5938_5938_0 │ 1 │ └───────────┴──────────────────────┴────────┘ 167 rows in set. Elapsed: 0.005 sec.
通常,分割槽是用來提升查詢效能。便於使用者靈活地管理資料子集。可以直接查詢分割槽、刪除分割槽等。
可以透過指定 where 子句或者使用隱藏列"_partition_id" 來檢視指定的分割槽。當然最好使用官方推薦的方式,在where子句中新增分割槽條件比較好。 有些特殊情況下,需要使用隱藏列"_partition_id"。
現在,讓我們看看分割槽表的查詢示例。假設我們的表(test.mytest_of_ti)對 “created_at ”列進行了分割槽。我們可以使用分割槽鍵列和隱藏的“_partition_id ”列訪問特定分割槽。此外,我們還可以使用“_partition_id ”查詢前 10 個分割槽。
SELECT count() FROM recoDB.mytest_of_ti WHERE toDate(created_at) = '2023-01-21' ┌─count()─┐ │ 9731 │ └─────────┘ ##################################### SELECT count() FROM test.mytest_of_ti WHERE _partition_id = '20230121' ┌─count()─┐ │ 9731 │ └─────────┘
SELECT _partition_id, count() FROM test.mytest_of_ti GROUP BY _partition_id ORDER BY 2 DESC LIMIT 10
解除安裝或附加Parts/Partitions
detach 操作可以將指定的 parts/partitions 移動到 detached 目錄。在重新附加之前,使用者無法訪問這些資料。預設情況下,detached 目錄位於"/var/lib/clickhouse/data/<DATABASE_NAME>/<TABLE_NAME>"中。
而 attach 操作可以將被解除安裝的parts/partitions 附加進來。語法如下所示:
#DETACH PART/PARTITION ALTER TABLE <DATABASE_NAME>.<TABLE_NAME> [ON CLUSTER <CLUSTER_NAME>] DETACH PARTITION|PART <PARTITION_EXPRESSION> #ATTACH PART/PARTITION ALTER TABLE <DATABASE_NAME>.<TABLE_NAME> [ON CLUSTER <CLUSTER_NAME>] ATTACH PARTITION|PART <PARTITION_EXPRESSION>
這裡的 PARTITION_EXPRESSION 是分割槽名、分割槽id或表示式自身。
這裡,分割槽表示式應該是分割槽名稱、分割槽 id 或表示式本身。
假設我們要從 “test.mytest_of_ti ”表中解除安裝任何指定日期的分割槽。
首先,找到指定日期的分割槽和parts名稱。如圖所示,該日期位於分割槽 “20231013 ”中,該分割槽有兩個part。
SELECT partition, name, partition_id FROM system.parts WHERE (database = 'test') AND (table = 'mytest_of_ti') AND (partition_id IN ( SELECT DISTINCT _partition_id FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' )) ┌─partition─┬─name─────────────┬─partition_id─┐ │ 20231013 │ 20231013_62_62_0 │ 20231013 │ │ 20231013 │ 20231013_78_78_0 │ 20231013 │ └───────────┴──────────────────┴──────────────┘
開始解除安裝分割槽"20231013",然後再附加進來。
-- Count related date before detached SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 78536 │ └─────────┘ -- detach partition ALTER TABLE test.mytest_of_ti DETACH PARTITION 20231013 Ok. -- Count related date after detached SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 0 │ └─────────┘
然後再重新附加進來:
--attach partition ALTER TABLE test.mytest_of_ti ATTACH PARTITION 20231013 Ok. --Count related date after attach partition SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 78536 │ └─────────┘
同樣對單個part做如上的操作。
--find parts for given date SELECT partition, name, partition_id FROM system.parts WHERE (database = 'test') AND (table = 'mytest_of_ti') AND (partition_id IN ( SELECT DISTINCT _partition_id FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' )) ┌─partition─┬─name───────────────┬─partition_id─┐ │ 20231013 │ 20231013_142_142_0 │ 20231013 │ │ 20231013 │ 20231013_143_143_0 │ 20231013 │ └───────────┴────────────────────┴──────────────┘ -- Count before detach part operation SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 78536 │ └─────────┘ -- detach any of the parts ALTER TABLE test.mytest_of_ti DETACH PART '20231013_142_142_0' Ok. -- Count after detach part operation SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 78406 │ └─────────┘ -- Attach related part ALTER TABLE test.mytest_of_ti ATTACH PART '20231013_142_142_0' -- Count after attach the part SELECT count() FROM test.mytest_of_ti WHERE toDate(created_at) = '2023-10-13' ┌─count()─┐ │ 78536 │ └─────────┘
也可以將源表的分割槽附加到目標表上,如下例所示,附加後資料不會從源表或目標表被刪除:
ALTER TABLE <DESTINATION_TABLE> [ON CLUSTER <CLUSTER_NAME>] ATTACH PARTITION <PARTITION EXPRESSION> FROM <SOURCE_TABLE>
不過,該操作需要目標表和源表滿足以下條件:
·結構相同
·分割槽鍵、排序鍵和主鍵相同
·儲存策略相同
刪除Parts/Partitions
刪除的parts/Partitions 在系統表 system.parts 中被標記為不活躍的,且刪除操作完成後,對應的parts/Partitions 會在 "/var/lib/clickhouse/data/<database_name>/<table_name>/" 中保留十分鐘。
-- Drop from table itself ALTER TABLE <DATABASE_NAME>.<TABLE_NAME> [ON CLUSTER <CLUSTER_NAME>] DROP PARTITION|PART 'PART/PARTITON EXPRESSION' -- Remove specified part/partition from detached folder ALTER TABLE <DATABASE_NAME>.<TABLE_NAME> [ON CLUSTER <CLUSTER_NAME>] DROP DETACHED PARTITION|PART 'PART/PARTITON EXPRESSION'
移動Parts/Partitions
可以將partitions移動到 Clickhouse 中的另一個表。在這種情況下,源表和目標表都具有相同的結構、分割槽鍵、按鍵排序、主鍵、儲存策略和引擎系列。
對於合併樹引擎表,移動的另一個選項是將parts或partitions移動到另一個磁碟或捲上。
-- Usage: ALTER TABLE <DATABASE_NAME.SOURCE_TABLE> [ON CLUSTER <CLUSTER_NAME>] MOVE PARTITION <PARTITION EXPRESSION> TO TABLE <DATABASE_NAME.DESTINATION_TABLE> -- 1. Create empty mytest_of_ti_new table same as the mytest_of_ti -- 2. Move 20231013 partition from mytest_of_ti to mytest_of_ti_new ALTER TABLE test.mytest_of_ti MOVE PARTITION '20231013' TO TABLE test.mytest_of_ti_new Ok. --3. Take partition count for 20231013 in source table SELECT count() FROM test.mytest_of_ti WHERE _partition_id = '20231013' ┌─count()─┐ │ 0 │ └─────────┘ --4 Take partition count for 20231013 in destination table SELECT count() FROM test.mytest_of_ti_new WHERE _partition_id = '20231013' Query id: 49319c73-c84f-4fbf-838d-ab787971eaad ┌─count()─┐ │ 78536 │ └─────────┘
移動 parts/partitions 到其它的磁碟或卷,需要設定一個儲存策略,並使用建立的策略建立一個新表。這裡不再講儲存策略。
-- Our table's(mytest_of_ti_with_storage_policy) policy is "vo1_to_vo2" -- and this volume contain 2 disks(vo1 and vo2) SELECT * FROM system.storage_policies WHERE policy_name = ( SELECT storage_policy FROM system.tables WHERE (database = 'test') AND (name = 'mytest_of_ti_with_storage_policy') ┌─policy_name─┬─volume_name─┬─volume_priority─┬─disks───┬─volume_type─┬─max_data_part_size─┬─move_factor─┬─prefer_not_to_merge─┐ │ vo1_to_vo2 │ vo1_volume │ 1 │ ['vo1'] │ JBOD │ 0 │ 0.1 │ 0 │ │ vo1_to_vo2 │ vo2_volume │ 2 │ ['vo2'] │ JBOD │ 0 │ 0.1 │ 0 │ └─────────────┴─────────────┴─────────────────┴─────────┴─────────────┴────────────────────┴─────────────┴─────────────────────┘ -- The 20231013 partition is stored under vo1 disk. SELECT partition, name, path FROM system.parts WHERE (database = 'test') AND (table = 'mytest_of_ti_with_storage_policy') AND (partition = '20231013') ┌─partition─┬─name───────────────┬─path────────────────────────────────────────────────────────────────────┐ │ 20231013 │ 20231013_107_107_0 │ /vo1/store/346/3465ekb6-231d-493d-94bc-518234d79b45/20231013_107_107_0/ │ └───────────┴────────────────────┴─────────────────────────────────────────────────────────────────────────┘ -- Let's move it to the vo2 disk ALTER TABLE test.mytest_of_ti_with_storage_policy MOVE PARTITION '20231013' TO DISK 'vo2' -Check the new volume SELECT partition, name, path FROM system.parts WHERE (database = 'test') AND (table = 'mytest_of_ti_with_storage_policy') AND (partition = '20231013') ┌─partition─┬─name───────────────┬─path────────────────────────────────────────────────────────────────────┐ │ 20231013 │ 20231013_107_107_0 │ /vo2/store/346/3465ekb6-231d-493d-94bc-518234d79b45/20231013_107_107_0/ │ └───────────┴────────────────────┴─────────────────────────────────────────────────────────────────────────┘ -- You can move parts and also you can move volume instead of disk