前文如下:
11.【clickhouse】ClickHouse从入门到放弃-概述
12.【clickhouse】ClickHouse从入门到放弃-环境搭建
13.【clickhouse】ClickHouse从入门到放弃-引擎
14.【clickhouse】ClickHouse从入门到放弃-实战
55.【clickhouse】ClickHouse从入门到放弃-概念场景
56.【clickhouse】ClickHouse从入门到放弃-架构概述
57.【clickhouse】ClickHouse从入门到放弃-update和delete的使用
58.【clickhouse】ClickHouse从入门到放弃-数据类型转换
59.【clickhouse】ClickHouse从入门到放弃-分区表
60.【clickhouse】ClickHouse从入门到放弃-MergeTree的创建方式
61.【clickhouse】ClickHouse从入门到放弃-MergeTree的存储结构
文档参考:《ClickHouse原理解析与应用实践(数据库技术丛书)(朱凯)》
2 数据分区
通过先前的介绍已经知晓在MergeTree中,数据是以分区目录的形式进行组织的,每个分区独立分开存储。借助这种形式,在对MergeTree进行数据查询时,可以有效跳过无用的数据文件,只使用最小的分区目录子集。这里有一点需要明确,在ClickHouse中,数据分区(partition)和数据分片(shard)是完全不同的概念。数据分区是针对本地数据而言的,是对数据的一种纵向切分。MergeTree并不能依靠分区的特性,将一张表的数据分布到多个ClickHouse服务节点。而横向切分是数据分片(shard)的能力,关于这一点将在后续章节介绍。本节将针对“数据分区目录具体是如何运作的”这一问题进行分析。
2.1 数据的分区规则
MergeTree数据分区的规则由分区ID决定,而具体到每个数据分区所对应的ID,则是由分区键的取值决定的。分区键支持使用任何一个或一组字段表达式声明,其业务语义可以是年、月、日或者组织单位等任何一种规则。针对取值数据类型的不同,分区ID的生成逻辑目前拥有四种规则:
(1)不指定分区键:如果不使用分区键,即不使用PARTITION BY声明任何分区表达式,则分区ID默认取名为all,所有的数据都会被写入这个all分区。
(2)使用整型:如果分区键取值属于整型(兼容UInt64,包括有符号整型和无符号整型),且无法转换为日期类型YYYYMMDD格式,则直接按照该整型的字符形式输出,作为分区ID的取值。
(3)使用日期类型:如果分区键取值属于日期类型,或者是能够转换为YYYYMMDD格式的整型,则使用按照YYYYMMDD进行格式化后的字符形式输出,并作为分区ID的取值。
(4)使用其他类型:如果分区键取值既不属于整型,也不属于日期类型,例如String、Float等,则通过128位Hash算法取其Hash值作为分区ID的取值。
数据在写入时,会对照分区ID落入相应的数据分区,下表列举了分区ID在不同规则下的一些示例。
PARTITION BY (length(Code),EventTime)
则最终的分区ID会是下面的模样:
2-20190501 2-20190
2.2 分区目录的命名规则
通过上一小节的介绍,我们已经知道了分区ID的生成规则。但是如果进入数据表所在的磁盘目录后,会发现MergeTree分区目录的完整物理名称并不是只有ID而已,在ID之后还跟着一串奇怪的数字,例如201905_1_1_0。那么这些数字又代表着什么呢?
众所周知,对于MergeTree而言,它最核心的特点是其分区目录的合并动作。但是我们可曾想过,从分区目录的命名中便能够解读出它的合并逻辑。在这一小节,我们会着重对命名公式中各分项进行解读,而关于具体的目录合并过程将会留在后面小节讲解。一个完整分区目录的命名公式如下所示:
PartitionID_MinBlockNum_MaxBlockNum_Level
如果对照着示例数据,那么数据与公式的对照关系会如同图所示一般。
上图中,201905表示分区目录的ID;1_1分别表示最小的数据块编号与最大的数据块编号;而最后的_0则表示目前合并的层级。接下来开始分别解释它们的含义:
(1)PartitionID:分区ID,无须多说,关于分区ID的规则在上一小节中已经做过详细阐述了。
(2)MinBlockNum和MaxBlockNum:顾名思义,最小数据块编号与最大数据块编号。ClickHouse在这里的命名似乎有些歧义,很容易让人与稍后会介绍到的数据压缩块混淆。但是本质上它们毫无关系,这里的BlockNum是一个整型的自增长编号。如果将其设为n的话,那么计数n在单张MergeTree数据表内全局累加,n从1开始,每当新创建一个分区目录时,计数n就会累积加1。对于一个新的分区目录而言,MinBlockNum与MaxBlockNum取值一样,同等于n,例如201905_1_1_0、201906_2_2_0以此类推。但是也有例外,当分区目录发生合并时,对于新产生的合并目录MinBlockNum与MaxBlockNum有着另外的取值规则。对于合并规则,我们留到下一小节再详细讲解。
(3)Level:合并的层级,可以理解为某个分区被合并过的次数,或者这个分区的年龄。数值越高表示年龄越大。Level计数与BlockNum有所不同,它并不是全局累加的。对于每一个新创建的分区目录而言,其初始值均为0。之后,以分区为单位,如果相同分区发生合并动作,则在相应分区内计数累积加1。
2.3 分区目录的合并过程
MergeTree的分区目录和传统意义上其他数据库有所不同。首先,MergeTree的分区目录并不是在数据表被创建之后就存在的,而是在数据写入过程中被创建的。也就是说如果一张数据表没有任何数据,那么也不会有任何分区目录存在。其次,它的分区目录在建立之后也并不是一成不变的。在其他某些数据库的设计中,追加数据后目录自身不会发生变化,只是在相同分区目录中追加新的数据文件。而MergeTree完全不同,伴随着每一批数据的写入(一次INSERT语句),MergeTree都会生成一批新的分区目录。即便不同批次写入的数据属于相同分区,也会生成不同的分区目录。也就是说,对于同一个分区而言,也会存在多个分区目录的情况。 在之后的某个时刻(写入后的10~15分钟,也可以手动执行optimize查询语句),ClickHouse会通过后台任务再将属于相同分区的多个目录合并成一个新的目录。已经存在的旧分区目录并不会立即被删除,而是在之后的某个时刻通过后台任务被删除(默认8分钟)。
属于同一个分区的多个目录,在合并之后会生成一个全新的目录,目录中的索引和数据文件也会相应地进行合并。新目录名称的合并方式遵循以下规则,其中:
·MinBlockNum:取同一分区内所有目录中最小的MinBlockNum值。 ·MaxBlockNum:取同一分区内所有目录中最大的MaxBlockNum值。 ·Level:取同一分区内最大Level值并加1。
合并目录名称的变化过程如图所示。
INSERT INTO partition_v5 VALUES (A, c1, '2019-05-01') INSERT INTO partition_v5 VALUES (B, c1, '2019-05-02') INSERT INTO partition_v5 VALUES (C, c1, '2019-06-01')
按照目录规,上述代码会创建3个分区目录。分区目录的名称由PartitionID、MinBlockNum、MaxBlockNum和Level组成,其中PartitionID根据6.2.1节介绍的生成规则,3个分区目录的ID依次为201905、201905和201906。而对于每个新建的分区目录而言,它们的MinBlockNum与MaxBlockNum取值相同,均来源于表内全局自增的BlockNum。BlockNum初始为1,每次新建目录后累计加1。所以,3个分区目录的MinBlockNum与MaxBlockNum依次为0_0、1_1和2_2。最后是Level层级,每个新建的分区目录初始Level都是0。所以3个分区目录的最终名称分别是201905_1_1_0、201905_2_2_0和201906_3_3_0。
假设在T1时刻,MergeTree的合并动作开始了,那么属于同一分区的201905_1_1_0与201905_2_2_0目录将发生合并。从图所示过程中可以发现,合并动作完成后,生成了一个新的分区201905_1_2_1。根据本节所述的合并规则,其中,MinBlockNum取同一分区内所有目录中最小的MinBlockNum值,所以是1;MaxBlockNum取同一分区内所有目录中最大的MaxBlockNum值,所以是2;而Level则取同一分区内,最大Level值加1,所以是1。 而后续T2时刻的合并规则,只是在重复刚才所述的过程而已。
至此,大家已经知道了分区ID、目录命名和目录合并的相关规则。最后,再用一张完整的示例图作为总结,描述MergeTree分区目录从创建、合并到删除的整个过程,如图所示。
2.4 本地分区模拟
####创建分区表 [root@localhost trade_spm_log]# clickhouse-client --user=default --password=clickhouse --host=127.0.0.1 --multiline ClickHouse client version 22.4.5.9 (official build). Connecting to 127.0.0.1:9000 as user default. Connected to ClickHouse server version 22.4.5 revision 54455. Warnings: * Linux transparent hugepage are set to "always". * Linux threads max count is too low. * Maximum number of threads is lower than 30000. There could be problems with handling a lot of simultaneous queries. localhost :) localhost :) CREATE TABLE IF NOT EXISTS default.partition_v5 ( `id` Int64 COMMENT '主键id', `code` String DEFAULT '' COMMENT 'code', `create_time` DateTime DEFAULT toDateTime(now(),'Asia/Shanghai') COMMENT '行为发生时间' )ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(create_time) ORDER BY (create_time,id) SETTINGS index_granularity = 8192; CREATE TABLE IF NOT EXISTS default.partition_v5 ( `id` Int64 COMMENT '主键id', `code` String DEFAULT '' COMMENT 'code', `create_time` DateTime DEFAULT toDateTime(now(), 'Asia/Shanghai') COMMENT '行为发生时间' ) ENGINE = ReplacingMergeTree PARTITION BY toYYYYMM(create_time) ORDER BY (create_time, id) SETTINGS index_granularity = 8192 Query id: 6412cac7-364c-4866-80a0-d54653695449 Ok. 0 rows in set. Elapsed: 0.021 sec. localhost :) show tables; SHOW TABLES Query id: 81ba034f-b52b-49b4-a4a9-8fda2a459f74 ┌─name───────────────────────────────────────────┐ │ .inner_id.4129b317-fe33-4377-92e0-4f1216305f3f │ │ partition_v5 │ │ trade_order_sum │ │ trade_order_view │ │ trade_spm │ │ trade_spm_log │ └────────────────────────────────────────────────┘ 6 rows in set. Elapsed: 0.003 sec. ###插入数据 INSERT INTO partition_v5 VALUES (1, 'A1', '2019-05-01'); INSERT INTO partition_v5 VALUES (2, 'B1', '2019-05-02'); INSERT INTO partition_v5 VALUES (3, 'C1', '2019-06-01'); ### 查看文件 [root@localhost default]# pwd /var/lib/clickhouse/data/default [root@localhost default]# ls ../ default mysql system [root@localhost default]# ls %2Einner_id%2E4129b317%2Dfe33%2D4377%2D92e0%2D4f1216305f3f trade_spm partition_v5 trade_spm_log trade_order_sum ###分别新增三条数据,查看版本信息 [root@localhost default]# cd partition_v5/ [root@localhost partition_v5]# ll total 4 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:18 201905_1_1_0 drwxr-x---. 2 clickhouse clickhouse 6 Nov 29 15:14 detached -rw-r-----. 1 clickhouse clickhouse 1 Nov 29 15:14 format_version.txt [root@localhost partition_v5]# ll total 4 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:18 201905_1_1_0 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:21 201905_2_2_0 drwxr-x---. 2 clickhouse clickhouse 6 Nov 29 15:14 detached -rw-r-----. 1 clickhouse clickhouse 1 Nov 29 15:14 format_version.txt [root@localhost partition_v5]# ll total 4 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:18 201905_1_1_0 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:21 201905_2_2_0 drwxr-x---. 2 clickhouse clickhouse 203 Nov 29 15:21 201906_3_3_0 drwxr-x---. 2 clickhouse clickhouse 6 Nov 29 15:14 detached -rw-r-----. 1 clickhouse clickhouse 1 Nov 29 15:14 format_version.txt [root@localhost partition_v5]#
2.5 查看分区信息
文档参考:clickhouse中如何查询分区表分区及表容量查询_扫地增的博客-CSDN博客_clickhouse 查看分区
clickhouse中如何查询分区表分区及表容量–这个问题相信大家在使用clickhouse分区表时都会经常遇到,其实clickhouse表的元数据信息都存储在system.parts表中,可以通过该表对clickhouse上所有表进行查询表容量大小、行数、压缩率及分区信息等进行查询了解。
1. system.parts表schema解析
system.parts表schema说明如下:
`partition`(String)-- 分区名称。 `name`(String)-- 数据部分的名称。 `part_type`(String)-- 数据部分的存储格式。 `active`(UInt8)-- 指示数据部分是否处于活动状态的标志。如果数据部分处于活动状态,则会在表中使用它。否则,将其删除。合并后,不活动的数据部分仍然保留。 `marks`(UInt64)-- 标记数。要获得数据部分中的大约行数,请乘以marks索引粒度(通常为8192)(此提示不适用于自适应粒度)。 `rows`(UInt64)-- 行数。 `bytes_on_disk`(UInt64)-- 所有数据片段的总大小(以字节为单位)。 `data_compressed_bytes`(UInt64)-- 数据片段中压缩数据的总大小。不包括所有辅助文件(例如,带标记的文件)。 `data_uncompressed_bytes`(UInt64)-- 数据片段中未压缩数据的总大小。不包括所有辅助文件(例如,带标记的文件)。 `marks_bytes`(UInt64)-- 带标记的文件的大小。 `modification_time`(DateTime) --包含数据片段的目录被修改的时间。这通常对应于数据零件创建的时间。 `remove_time`(DateTime)-- 数据片段变为非活动状态的时间。 `refcount`(UInt32)-- 使用数据片段的位置数。大于2的值表示在查询或合并中使用了数据部分。 `min_date`(Date)-- 数据片段中日期键的最小值。 `max_date`(Date) -- 数据片段中日期键的最大值。 `min_time`(DateTime)-- 数据片段中日期和时间键的最小值。 `max_time`(DateTime)-- 数据片段中日期和时间键的最大值。 `partition_id`(String)-- 分区的ID。 `min_block_number`(UInt64)-- 合并后组成当前部分的数据片段的最小数量。 `max_block_number`(UInt64)-- 合并后组成当前部分的最大数据片段数。 `level`(UInt32)-- 合并树的深度。零表示当前零件是通过插入而不是通过合并其他零件来创建的。 `data_version`(UInt64)-- 用于确定应将哪些突变应用于数据部分(版本高于的突变data_version)的编号。 `primary_key_bytes_in_memory`(UInt64)-- 主键值使用的内存量(以字节为单位)。 `primary_key_bytes_in_memory_allocated`(UInt64)-- 为主键值保留的内存量(以字节为单位)。 `is_frozen`(UInt8)-- 显示分区数据备份存在的标志。1,备份存在。0,备份不存在。有关更多详细信息,请参见“冻结分区”。 `database`(String)-- 数据库的名称。 `table`(String)-- 表的名称。 `engine`(String)-- 不带参数的表引擎的名称。 `path`(字符串)-- 包含数据零件文件的文件夹的绝对路径。 `disk`(字符串)-- 存储数据部分的磁盘的名称。 `hash_of_all_files`(字符串)-- 压缩文件的sipHash128。 `hash_of_uncompressed_files`(String)-- 未压缩文件(带有标记的文件,索引文件等)的sipHash128。 `uncompressed_hash_of_compressed_files`(String)-- 压缩文件中的数据的sipHash128,就好像它们是未压缩的一样。 `delete_ttl_info_min`(DateTime)-- TTL DELETE规则的日期和时间键的最小值。 `delete_ttl_info_max`(DateTime)-- TTL DELETE规则的日期和时间键的最大值。 `move_ttl_info.expression`(Array(String))-- 表达式数组。每个表达式定义一个TTL MOVE规则。 `move_ttl_info.min`(Array(DateTime))-- 日期和时间值的数组。每个元素都描述了TTL MOVE规则的最小键值。 `move_ttl_info.max`(Array(DateTime))-- 日期和时间值的数组。每个元素都描述了TTL MOVE规则的最大键值。 `bytes`(UInt64)-- bytes_on_disk的别名。 `marks_size`(UInt64)-- marks_bytes的别名。
2.查看数据库总体容量、行数、压缩率
localhost :) SELECT sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts; SELECT sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts Query id: f774cf34-b701-4606-b28d-045509da625c ┌────总行数─┬─原始大小──┬─压缩大小─┬─压缩率─┐ │ 401403491 │ 25.93 GiB │ 1.84 GiB │ 7 │ └───────────┴───────────┴──────────┴────────┘ 1 rows in set. Elapsed: 0.040 sec. Processed 1.09 thousand rows, 26.11 KB (27.00 thousand rows/s., 647.89 KB/s.)
3.查看数据表容量、行数、压缩率
在此查询一张测试标签表的信息
localhost :) SELECT table AS `表名`, sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts WHERE table IN ('partition_v5') GROUP BY table; SELECT table AS `表名`, sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts WHERE table IN ('partition_v5') GROUP BY table Query id: 7a8740f9-c65e-4cd5-aae3-e1ef3978160a ┌─表名─────────┬─总行数─┬─原始大小─┬─压缩大小─┬─压缩率─┐ │ partition_v5 │ 3 │ 45.00 B │ 279.00 B │ 620 │ └──────────────┴────────┴──────────┴──────────┴────────┘ 1 rows in set. Elapsed: 0.017 sec.
4.查看数据表分区信息
查看测试表在19年105月的分区信息
localhost :) SELECT partition AS `分区`, sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts WHERE (database IN ('default')) AND (table IN ('partition_v5')) GROUP BY partition ORDER BY partition ASC; SELECT partition AS `分区`, sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts WHERE (database IN ('default')) AND (table IN ('partition_v5')) GROUP BY partition ORDER BY partition ASC Query id: 5e6c75d9-33a1-492d-af0b-b8ee803de3e1 ┌─分区───┬─总行数─┬─原始大小─┬─压缩大小─┬─压缩率─┐ │ 201905 │ 2 │ 30.00 B │ 186.00 B │ 620 │ │ 201906 │ 1 │ 15.00 B │ 93.00 B │ 620 │ └────────┴────────┴──────────┴──────────┴────────┘ 2 rows in set. Elapsed: 0.018 sec.
SELECT partition AS `分区`, sum(rows) AS `总行数`, formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`, round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100, 0) AS `压缩率` FROM system.parts WHERE (database IN ('default')) AND (table IN ('partition_v5')) AND (partition LIKE '201905%') GROUP BY partition ORDER BY partition ASC Query id: 02194885-77cf-4740-a9d6-7bf638c090fb ┌─分区───┬─总行数─┬─原始大小─┬─压缩大小─┬─压缩率─┐ │ 201905 │ 2 │ 30.00 B │ 186.00 B │ 620 │ └────────┴────────┴──────────┴──────────┴────────┘ 1 rows in set. Elapsed: 0.006 sec.
5.查看数据表字段的信息
SELECT column AS `字段名`, any(type) AS `类型`, formatReadableSize(sum(column_data_uncompressed_bytes)) AS `原始大小`, formatReadableSize(sum(column_data_compressed_bytes)) AS `压缩大小`, sum(rows) AS `行数` FROM system.parts_columns WHERE (database = 'default') AND (table = 'partition_v5') GROUP BY column ORDER BY column ASC Query id: 607acff1-d507-482a-b42c-c93e8ec721dc ┌─字段名──────┬─类型─────┬─原始大小─┬─压缩大小─┬─行数─┐ │ code │ String │ 0.00 B │ 0.00 B │ 3 │ │ create_time │ DateTime │ 0.00 B │ 0.00 B │ 3 │ │ id │ Int64 │ 0.00 B │ 0.00 B │ 3 │ └─────────────┴──────────┴──────────┴──────────┴──────┘ 3 rows in set. Elapsed: 0.004 sec.
6. system.parts_columns表 schema解析
system.parts_columns表 schema说明如下:
`partition`(String)-- 分区名称。 `name`(String)-- 数据片段的名称。 `part_type`(String)-- 数据片段的存储格式。 `active`(UInt8)-- 指示数据部分是否处于活动状态的标志。如果数据部分处于活动状态,则会在表中使用它。否则,将其删除。合并后,不活动的数据部分仍然保留。 `marks`(UInt64)-- 标记数。要获得数据部分中的大约行数,请乘以marks索引粒度(通常为8192)(此提示不适用于自适应粒度)。 `rows`(UInt64)-- 行数。 `bytes_on_disk`(UInt64)-- 所有数据部分文件的总大小(以字节为单位)。 `data_compressed_bytes`(UInt64)-- 数据部分中压缩数据的总大小。不包括所有辅助文件(例如,带标记的文件)。 `data_uncompressed_bytes` (UInt64) --数据部分中未压缩数据的总大小。不包括所有辅助文件 (例如,带标记的文件)。 `marks_bytes` (UInt64) --带有标记的文件的大小。 `modification_time` (DateTime) --包含数据部分的目录被修改的时间。这通常对应于数据零件创建的时间。 `remove_time` (DateTime) --数据部分变为非活动状态的时间。 `refcount` (UInt32) --使用数据部分的位置数。大于2的值表示在查询或合并中使用了数据部分。 `min_date` (Date) --数据部分中日期键的最小值。 `max_date` (Date) --数据部分中日期密钥的最大值。 `partition_id` (String) --分区的ID。 `min_block_number` (UInt64) --合并后组成当前部分的数据部分的最小数量。 `max_block_number` (UInt64) --合并后组成当前部分的最大数据部分数。 `level` (UInt32) --合并树的深度。零表示当前零件是通过插入而不是通过合并其他零件来创建的。 `data_version` (UInt64) --用于确定应将哪些突变应用于数据部分 (版本高于的突变data_version)的编号。 `primary_key_bytes_in_memory` (UInt64) --主键值使用的内存量 (以字节为单位)。 `primary_key_bytes_in_memory_allocated` (UInt64) --为主键值保留的内存量 (以字节为单位)。 `database` (String) --数据库名称。 `table` (String) --表的名称。 `engine` (String) --不带参数的表引擎的名称。 `disk_name` (String) --存储数据部分的磁盘的名称。 `path` (String) --包含数据零件文件的文件夹的绝对路径。 `column` (String) --列的名称。 `type` (String) --列类型。 `column_position` (UInt64) --以1开头的表中列的顺序位置。 `default_kind` (字符串) --表达类型 (DEFAULT,MATERIALIZED,ALIAS作为默认值),或者如果没有定义它为空字符串。 `default_expression` (String) --默认值的表达式,如果未定义,则为空字符串。 `column_bytes_on_disk` (UInt64) --列的总大小,以字节为单位。 `column_data_compressed_bytes` (UInt64) --列中压缩数据的总大小,以字节为单位。 `column_data_uncompressed_bytes` (UInt64) --列中解压缩数据的总大小,以字节为单位。 `column_marks_bytes` (UInt64) --带标记的列的大小,以字节为单位。 `bytes` (UInt64) --的别名bytes_on_disk。 `marks_size` (UInt64) --的别名marks_bytes。