ClickHouse 与 Parquet(第一篇) :构建快速 Lakehouse 分析的坚实基础

图片

本文字数:13159;估计阅读时间:33 分钟

作者:Tom Schreiber

本文在公众号【ClickHouselnc】首发

图片

简要摘要:ClickHouse 天然适配 Parquet 格式。Parquet 是 Apache Iceberg 和 Delta Lake 等开放表格式背后的核心存储形式,ClickHouse 多年来持续针对其进行了深入优化。

本文将深入解析 ClickHouse 查询引擎的内部机制,展示其如何无需数据导入即可直接查询 Parquet 文件,并且查询性能往往超过很多系统在自有格式下的表现。我们还将介绍未来的一些优化方向。

这是我们新系列的开篇文章,聚焦 ClickHouse 如何从底层能力出发,构建起高性能的 Lakehouse 分析能力。

值得提前指出的是:ClickHouse 并不是“正在为 Lakehouse 做准备”,它早已准备就绪。

从偶然到有意:为 Lakehouse 而生的引擎

有时候,技术的发展方向恰好与既有路径不谋而合。

尽管 ClickHouse 的设计初衷并非为 Lakehouse 架构服务(当 Iceberg 和 Delta Lake 出现时,ClickHouse 已是一个成熟的数据库系统),但它恰好拥有高度契合的能力。ClickHouse 对 Parquet 提供一等支持,并支持直接查询文件格式,早已原生支持了许多 Lakehouse 模式。

ClickHouse 查询引擎始终将“支持多种格式、支持远程位置的数据访问”视为核心功能。无论是先导入再查询,还是直接查询外部数据,这种灵活性是 ClickHouse 一贯的优势。

如今所谓的 Lakehouse 架构,其核心理念——任意部署、任意查询、灵活访问数据——正是 ClickHouse 多年来不断强化的能力体现:

任意部署:ClickHouse 引擎可灵活部署于本地服务器、云平台、独立模式,甚至嵌入式运行环境中。

图片

任意查询:除了为 MergeTree 原生表格式进行了极致优化,ClickHouse 还能直接查询外部格式,无需预先导入。大多数数据库在运行查询前都必须将 Parquet 等文件加载转换为内部格式,而 ClickHouse 可以跳过这个步骤。查询引擎原生支持超过 70 种文件格式,并提供完整 SQL 功能:包括 JOIN、窗口函数和 160 多种聚合函数,均可在原始文件上直接执行。支持的格式包括 Parquet、JSON、CSV、Arrow 等。

图片

灵活访问数据:ClickHouse 提供 80 多种内置集成,可与各种外部系统和对象存储平台无缝连接,例如 S3、GCP、Azure 等。

这些能力使 ClickHouse 成为 Lakehouse 场景的理想技术基础。ClickHouse 能够直接查询存储在对象存储上的 Apache Iceberg 表,这些表大多采用 Parquet 格式保存数据。

图片

同时,ClickHouse 查询引擎支持多种运行模式,可灵活部署在各种场景中:无论是靠近对象存储的计算节点、多租户 SaaS 系统内部、嵌入在使用 pandas 的 Jupyter Notebook 中,还是作为无状态函数运行于 AWS Lambda 环境中,都可以胜任。

引擎剖析:ClickHouse 如何高效查询 Parquet 文件

本文将深入介绍 ClickHouse 如何处理 Lakehouse 架构中关键的数据存储格式之一:Parquet。

  • ClickHouse 目前查询 Parquet 文件的性能究竟如何?

  • 与其原生的 MergeTree 表相比表现如何?

  • 在 ClickHouse 支持的 70 多种外部格式中,还有哪些更快的选择?

  • 未来还有哪些优化方向?

这些问题将在本文中一一解答。文章也开启了一个全新系列,聚焦 ClickHouse 作为高性能 Lakehouse 引擎的技术演进。本篇将从基础的数据格式 Parquet 入手,该格式正是 Apache Iceberg 和 Delta Lake 等开放表格式的底层支撑。

我们将先解析当前版本中 Parquet 读取器的实现机制,并探讨其性能优势。随后,我们将在真实分析场景中对其进行基准测试,展示当前表现,并预告未来的改进方向。

正如前文所述,ClickHouse 查询引擎支持直接查询包括 Parquet 在内的 70 多种文件格式,完全无需预先导入数据。针对不同格式的读取器可以作为插件集成进引擎,工作流程如下:

图片

1. 读取器读取外部文件并解析内容;

2. 将解析后的数据转换为 ClickHouse 的内存格式;

3. 查询引擎对其执行查询逻辑;

4. 输出最终结果。

本节将重点聚焦 Parquet 读取器,它与 ClickHouse 查询引擎的协同,是实现高性能文件查询的核心组件。

当前 Parquet 读取器的机制与演进方向

值得一提的是,虽然 MergeTree 依然是 ClickHouse 的原生表引擎,但我们早在三年前就已着手优化对 Parquet 的支持。这一努力旨在将 ClickHouse 打造为全球最快的 Parquet 查询引擎。

目前的 Parquet 读取器使用 Arrow 库将文件解析为 Arrow 格式,再转换为 ClickHouse 的原生内存格式,以供执行查询。在下文中,我们将具体分析这一实现的能力边界。

一个全新的原生 Parquet 读取器正在开发中,目标是完全移除 Arrow 中间层,直接将文件加载进 ClickHouse 内存结构。同时,该实现将带来更强的并行性和更高的 I/O 效率。项目名称是 “Yet Another Parquet Reader”(YAPR)——顾名思义,这是 ClickHouse 的第三代 Parquet 读取器。第一代(input_format_parquet_use_native_reader)未完成;第二代(v2)虽有 Pull Request,但未正式上线;而第三代 v3 正在积极推进中。

我们本可以等新版本完成后再发布本篇文章,但当前版本的基准测试为后续性能对比提供了可靠的参考基线。在后续的文章中,我们将重点展示新读取器带来的提升。

<think>我们已知用户意图:将Parquet文件数据插入到ClickHouse数据库。 根据引用[1]提到可以使用DataX工具,其中涉及clickhousewriter和hdfsreader插件(如果数据在HDFS上)。但用户的数据源是Parquet文件,可能存储在本地或HDFS上。 另外,引用[2]提到ClickHouse的基本INSERT语法,但直接INSERT VALUES不适合大数据量的Parquet文件。 引用[3]展示了Hive中的Parquet表结构,并提到数据量达到亿级,因此我们需要高效的方法。 推荐方法: 1. 使用DataX工具(适合从HDFS读取Parquet文件并写入ClickHouse) 2. 使用ClickHouse的本地表引擎(如File)或集成引擎(如HDFS)直接查询Parquet文件,然后插入到目标表。 3. 使用clickhouse-local工具(本地处理Parquet文件并插入) 4. 使用INSERT SELECT方式(如果Parquet文件已经通过某种方式挂载到ClickHouse中) 具体步骤: 方法一:使用DataX(适合从HDFS读取) 步骤: 1) 安装DataX 2) 配置hdfsreader插件(指定Parquet文件路径,并配置列信息) 3) 配置clickhousewriter插件(指定ClickHouse表信息) 方法二:使用ClickHouse集成表引擎(HDFS引擎或File引擎) 步骤: 1)ClickHouse中创建一张表,使用HDFS引擎或File引擎指向Parquet文件(注意:File引擎需要Parquet文件在ClickHouse服务器本地) 2) 然后创建目标表(使用MergeTree引擎) 3) 使用INSERT INTO ... SELECT ... 将数据从引擎表导入到目标表 方法三:使用clickhouse-local命令行工具(适合本地文件处理) 步骤: 1) 使用clickhouse-local工具,通过SQL语句读取本地Parquet文件并插入到远程ClickHouse服务器(或者先导入到本地表,再传输) 方法四:使用URL表引擎(如果Parquet文件在HTTP服务器上) 步骤: 1) 使用url表引擎指定Parquet文件的URL 2) 然后使用INSERT SELECT导入 考虑到用户数据量可能很大(如引用[3]中的亿级数据),推荐使用DataX(支持分布式和并行)或者使用集成表引擎(HDFS引擎)的方式。 下面我们详细说明两种常用方法: 方法一:使用DataX 1. 安装DataX(略) 2. 编写DataX任务配置文件,例如parquet_to_ck.json: ```json { "job": { "setting": { "speed": { "channel": 4 // 并发数 } }, "content": [ { "reader": { "name": "hdfsreader", "parameter": { "path": "/path/to/your/data.parquet", // HDFS上的路径 "defaultFS": "hdfs://namenode:port", "fileType": "parquet", "column": [ { "index": 0, // 列索引,从0开始,或使用列名(需要DataX支持) "type": "string" // 对应Parquet中的数据类型 }, // ... 其他列 ], "haveKerberos": false // 如果HDFS有Kerberos认证,需配置 } }, "writer": { "name": "clickhousewriter", "parameter": { "connection": [ { "jdbcUrl": "jdbc:clickhouse://clickhouse-server:8123/database", "table": ["table_name"] } ], "username": "default", "password": "", "column": ["col1", "col2", ...], // 列名,reader的列顺序一致 "postSql": [], // 执行后SQL "preSql": [] // 执行前SQL,如清空表 } } } ] } } ``` 3. 执行DataX任务:`python datax.py parquet_to_ck.json` 方法二:使用ClickHouse的HDFS表引擎(如果Parquet文件在HDFS上) 步骤: 1)ClickHouse中创建一张外部表,指向HDFS上的Parquet文件: ```sql CREATE TABLE hdfs_engine_table ( MACH_ID String, MACH_IP String, CREATE_TIME String, IPQC_ONLINEID String, INS_TIME String, PROD_SN String, DOT_ID String, DOT_VALUE String ) ENGINE = HDFS('hdfs://namenode:port/path/to/data.parquet', 'Parquet') ``` 2) 创建目标表(根据实际需求选择引擎,一般为MergeTree家族引擎): ```sql CREATE TABLE target_table ( MACH_ID String, MACH_IP String, CREATE_TIME String, IPQC_ONLINEID String, INS_TIME String, PROD_SN String, DOT_ID String, DOT_VALUE String ) ENGINE = MergeTree ORDER BY (MACH_ID, CREATE_TIME) ``` 3) 将数据从外部表导入到目标表: ```sql INSERT INTO target_table SELECT * FROM hdfs_engine_table ``` 注意:如果Parquet文件在本地,可以使用File引擎: ```sql CREATE TABLE file_engine_table ( ... ) ENGINE = File(Parquet, '/path/to/local/data.parquet') ``` 方法三:使用clickhouse-local(适合本地文件处理) 步骤: 1)Parquet文件放在ClickHouse服务器本地(或者可以访问的位置) 2) 使用clickhouse-local工具读取Parquet文件并插入到远程ClickHouse表: ```bash clickhouse-local --query="INSERT INTO TABLE target_table FORMAT Parquet" < data.parquet ``` 但是,这个命令实际上是将本地的Parquet文件数据以INSERT的方式发送到远程表,需要先配置远程连接。更简单的方式是直接使用SELECT读取Parquet文件然后通过HTTP接口插入: ```bash # 将本地Parquet文件导入到远程ClickHouseclickhouse-local --query="SELECT * FROM file('data.parquet', Parquet)" | curl 'http://clickhouse-server:8123/?query=INSERT%20INTO%20target_table%20FORMAT%20TabSeparated' --data-binary @- ``` 注意:这种方法可能因为格式问题需要调整(TabSeparated格式要求),或者使用其他格式(如Native格式)更高效,但需要配置。 根据实际情况选择方法。如果数据在HDFS上,推荐使用DataX或HDFS引擎;如果数据在本地且数据量不大,可以使用clickhouse-local。 注意事项: - 数据类型映射:确保Parquet文件中的数据类型ClickHouse表中的数据类型兼容。 - 性能:对于大数据量,建议分批导入或使用并行方式。 - 网络:如果数据在远程,确保网络畅通。 相关问题: 1. 如何优化从HDFS导入Parquet文件到ClickHouse的性能? 2. 在导入过程中出现数据类型不匹配的错误,如何解决? 3. 除了DataX,还有哪些工具可以将Parquet数据导入ClickHouse? 4. 如何将Hive表中的Parquet数据导入ClickHouse?</think>要将 Parquet 文件数据插入到 ClickHouse 数据库中,可通过以下几种高效方法实现: --- ### 方法一:使用 DataX 工具(推荐) 适用于大数据量迁移(如亿级数据): 1. **安装 DataX** 下载并配置 [DataX](https://github.com/alibaba/DataX),确保安装 `hdfsreader` 和 `clickhousewriter` 插件。 2. **配置任务 JSON 文件** ```json { "job": { "content": [{ "reader": { "name": "hdfsreader", "parameter": { "path": "/hdfs/path/data.parquet", // Parquet 文件路径 "defaultFS": "hdfs://namenode:port", "fileType": "parquet", // 指定文件格式 "column": [ // 列定义(需 Parquet 结构匹配) {"name": "MACH_ID", "type": "string"}, {"name": "MACH_IP", "type": "string"}, ... // 其他字段 ] } }, "writer": { "name": "clickhousewriter", "parameter": { "connection": [{ "jdbcUrl": "jdbc:clickhouse://ch-server:8123/db_name", "table": "target_table" // ClickHouse 目标表名 }], "username": "default", "password": "", "column": ["MACH_ID", "MACH_IP", ...] // reader 列顺序一致 } } }] } } ``` 3. **执行迁移** ```bash python datax.py job.json ``` **优点**:支持分布式读取、断点续传,适合生产环境[^1]。 --- ### 方法二:通过 ClickHouse 表引擎直接读取 若 Parquet 文件在 HDFS 或本地: 1. **创建 HDFS 引擎表**(文件在 HDFS) ```sql CREATE TABLE hdfs_parquet_engine ( MACH_ID String, MACH_IP String, ... ) ENGINE = HDFS('hdfs://namenode:port/path/data.parquet', 'Parquet') ``` 2. **插入目标表** ```sql INSERT INTO target_table SELECT * FROM hdfs_parquet_engine ``` --- ### 方法三:使用 `clickhouse-local` 命令行工具 适合本地 Parquet 文件快速导入: ```bash clickhouse-local \ --query "INSERT INTO TABLE target_table FORMAT Parquet" \ < local_data.parquet ``` 或通过 SELECT 转换数据: ```bash clickhouse-local \ --query "SELECT * FROM file('data.parquet', Parquet)" \ | clickhouse-client --query "INSERT INTO target_table FORMAT TSV" ``` --- ### 关键注意事项 1. **数据类型映射** Parquet 的 `STRING` 对应 ClickHouse 的 `String`,时间类型需显式转换(如 `CAST(INS_TIME AS DateTime)`)[^2]。 2. **性能优化** - 批量插入时使用 `INSERT ... VALUES (...), (...), ...` 格式[^2]。 - 调整 `max_insert_block_size`(默认 1,048,576 行)。 3. **复杂场景** 若需增量更新,可在 ClickHouse 中使用 `ReplacingMergeTree` 引擎去重[^3]。 --- ### 示例完整流程(Hive → ClickHouse) 1. Hive 导出 Parquet 到 HDFS: ```sql INSERT OVERWRITE DIRECTORY '/hdfs/path' STORED AS PARQUET SELECT * FROM hive_table; ``` 2. 通过 DataX 或 HDFS 引擎表导入 ClickHouse。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值