Day 26|Apache Doris 湖仓一体:Multi-Catalog、Hive、Iceberg、Hudi、Paimon 与 JDBC Catalog
课程阶段:第六阶段——湖仓与 AI
建议学习时长:4~6 小时
实验基线:Apache Doris 4.0.8 Stable / 4.1.3 Latest
本文核验日期:2026-08-18
前二十五天,我们已经完成 Doris 从基础认知、表设计、数据导入、查询加速,到执行内核、存储引擎、生产运维和安全治理的完整学习。企业数据平台继续向前演进时,数据通常已经分布在多个系统中:历史明细位于 Hive,开放表格式使用 Iceberg,CDC 结果沉淀在 Hudi,实时湖仓使用 Paimon,客户和组织信息仍保存在 MySQL、Oracle 或 PostgreSQL,面向高并发分析的结果则进入 Doris 内部表。
这类架构的难点集中在五个方面:
- 同一条分析链路需要访问多个元数据系统和存储系统;
- 数据搬运会引入延迟、重复存储、调度依赖和一致性成本;
- 远端文件数量、分区布局、对象存储延迟会直接影响查询稳定性;
- 元数据缓存带来性能收益,也会影响 Schema、分区和文件变化的可见时间;
- 不同表格式的查询语义、增量能力、历史版本和写回能力存在明显差异。
Apache Doris 的 Multi-Catalog 提供统一的三层命名空间和外部数据连接能力。学习者可以通过一套 SQL 访问 Doris 内部表、Hive、Iceberg、Hudi、Paimon 和关系数据库,并在联邦查询、数据入仓、外部写回三条路径之间做出工程选择。

一、今天要掌握什么
完成本篇后,学习者应具备以下能力:
- 能够解释 Lakehouse、Multi-Catalog、External Catalog 与 Internal Catalog 的职责;
- 能够说明 FE 元数据控制面和 BE 数据读取面的协同过程;
- 能够根据 Hive、Iceberg、Hudi、Paimon 和 JDBC 的特点选择 Catalog;
- 能够使用
catalog.database.table编写跨 Catalog 查询; - 能够判断一条需求适合联邦查询、入仓加速或外部写回;
- 能够设计 Metadata Cache 的 TTL、容量、刷新和观测方案;
- 能够启用 Data Cache,验证冷查询、热查询和 Warm Up 的效果;
- 能够通过分区、文件、Row Group、列裁剪和谓词下推减少远端扫描;
- 能够为外部表收集统计信息,帮助 CBO 选择 Join 顺序和分布策略;
- 能够使用 Compute Node 隔离湖仓重查询;
- 能够评估 Kerberos、IAM Role、JDBC Driver、网络连通和权限治理;
- 能够完成一份具有正确性、性能、稳定性和回滚条件的湖仓 POC 报告。
截至核验日,Apache Doris 官网将 4.1.3 标记为 Latest,将 4.0.8 标记为 Stable。本文以 4.x 通用能力为主体,对 include_table_list、统一 meta.cache.*、Paimon JDBC Catalog、Iceberg V3 Row Lineage 和 Data Cache 查询级限制等版本敏感能力单独标注。
二、湖仓一体解决的核心问题
传统数仓和数据湖常常形成两套独立体系。数据湖保留成本较低、格式开放、历史跨度大的原始数据;数仓提供稳定 Schema、查询性能、并发和数据服务。两套体系之间通过 Spark、Flink、Airflow 或自研调度不断搬运数据。
数据搬运具有明确价值。高频数据进入 Doris 内部表后,可以使用数据模型、索引、物化视图、Row Store、Workload Group 和高并发点查能力。问题在于,所有数据都提前搬运会产生新的成本:
- 数百 TB 历史数据需要重复存储;
- 新增一个分析问题可能先等待同步链路上线;
- 同一份数据在湖、仓和下游应用之间形成多个版本;
- 回补、重跑和 Schema 演进会扩大调度复杂度;
- 低频数据长期占用高性能存储。
Doris Lakehouse 提供四类能力:
- 灵活访问:通过 Catalog 连接多种元数据服务和数据源;
- 高性能处理:使用 MPP、向量化、Pipeline、裁剪、缓存和统计信息执行外表查询;
- 多源联邦:在同一条 SQL 中 Join 内部表、湖表和 JDBC 小表;
- 数据处理闭环:把外部数据写入 Doris,或把处理结果写回 Hive、Iceberg、JDBC 等支持的外部系统。

Lakehouse 架构的价值来自数据路径选择。高频、稳定、需要低尾延迟的数据适合进入 Doris 内部表;低频历史数据可以保留在 HDFS 或对象存储;探索和核验需求可以先使用联邦查询;确认长期价值后,再通过 INSERT INTO SELECT、CTAS、异步物化视图或周期任务完成物化。
三、Multi-Catalog 的基本模型
3.1 两类 Catalog
Doris 中存在两类 Catalog:
| 类型 | 说明 |
|---|---|
| Internal Catalog | 固定名称为 internal,管理 Doris 内部表,不能创建、改名或删除 |
| External Catalog | 连接外部数据源,可以创建、修改、刷新和删除 |
External Catalog 保存连接属性、认证信息、名称映射和缓存配置。远端 Schema 仍由 HMS、Iceberg REST、Paimon Catalog 或关系数据库管理,数据文件仍位于 HDFS、S3、OSS、COS、OBS、GCS、Azure Blob 等存储系统。
删除 External Catalog 只会移除 Doris 中的映射。远端 Metastore、表和文件不会随之删除。这个边界对生产变更非常重要,Catalog 删除后的恢复重点是重建配置、凭据、权限和缓存策略。
3.2 三层命名空间
所有数据对象统一使用:
catalog.database.table
例如:
SELECT *
FROM hive_prod.sales_dw.fact_sales;
Doris 提供三种常见会话方式:
-- 方式一:完整限定名
SELECT * FROM iceberg_prod.sales.product_dim;
-- 方式二:切换 Catalog 和 Database
SWITCH iceberg_prod;
USE sales;
SELECT * FROM product_dim;
-- 方式三:直接切换到 catalog.database
USE iceberg_prod.sales;
SELECT * FROM product_dim;
用户属性 default_init_catalog 可以设置默认 Catalog。MySQL 命令行或 JDBC URL 显式指定 catalog.database 时,连接参数具有更高优先级。

3.3 Catalog 级过滤和大小写
大型 HMS 可能包含数千个数据库和数十万张表。每次完整枚举会增加 Metastore 压力,也可能导致客户端执行 SHOW TABLES 超时。Catalog 通用属性可以收敛同步范围:
CREATE CATALOG hive_prod PROPERTIES (
"type" = "hms",
"hive.metastore.uris" = "thrift://hms-host:9083",
"include_database_list" = "sales_dw,ods",
"include_table_list" = "sales_dw.fact_sales,ods.raw_events"
);
include_table_list 从 4.1.0 起支持。Catalog 级 lower_case_table_names 和 lower_case_database_names 同样从 4.1.0 起提供。远端存在 MyTable 与 mytable 这类仅大小写不同的对象时,启用大小写不敏感模式会产生名称冲突,上线前需要完整扫描和验证。
四、控制面和数据面怎样协同
理解湖仓查询,需要把元数据和数据文件分开观察。
4.1 FE:元数据与计划控制面
FE 负责:
- 解析三层对象名称;
- 校验 Catalog、Database、Table 和 Column 权限;
- 从本地缓存或远端 Metastore 获取 Schema、分区和文件信息;
- 进行分区裁剪、谓词下推、列裁剪、Join Reorder 和分布策略选择;
- 生成外表 Scan 的 Split 和 PlanFragment;
- 调度 BE 执行,并汇总 Profile 和结果。
4.2 BE:远端数据读取与计算面
BE 负责:
- 访问 HDFS、对象存储或关系数据库;
- 读取 Parquet、ORC、Hudi、Paimon、Iceberg 文件和删除文件;
- 执行解压、解码、谓词过滤、Runtime Filter、Join、聚合和排序;
- 把热点远端文件写入 Data Cache;
- 通过 Exchange 传输跨节点中间结果。
因此,Catalog 创建成功只证明 FE 可以保存配置和访问部分元数据。生产验收还要确认所有参与执行的 BE 能访问远端存储、DNS、证书、Kerberos Keytab、对象存储 Endpoint 和 JDBC 数据库。

五、五类 Catalog 的选择方法

5.1 Hive Catalog:既有离线数仓的入口
Hive Catalog 通过 Hive Metastore 或兼容服务获取数据库、表、Schema、分区和 Location。除了 Hive 表,它还可以读取使用 HMS 保存元数据的 Iceberg 或 Hudi 表。对于 Iceberg,官方更推荐使用专用 Iceberg Catalog,以获得更完整的 Snapshot、Branch、Tag、系统表和写入语义。
Hive Catalog 适合三类任务:
- 直接查询 Hive 历史明细;
- 将 Hive 数据写入 Doris 内部表;
- 通过 Doris 处理后写回 Hive 表。
当前官方支持 Hive 1.x、2.x、3.x、4.x,常见文件格式包括 Parquet、ORC、Text、CSV 和 JSON。数据可以位于 HDFS,也可以位于多种对象存储。
典型创建语句:
CREATE CATALOG hive_prod PROPERTIES (
"type" = "hms",
"hive.metastore.uris" = "thrift://hms-host:9083",
"fs.defaultFS" = "hdfs://nameservice1",
"hadoop.username" = "doris"
);
fs.defaultFS 对只读查询可以省略;需要从 Doris 创建 Hive 表或写回数据时应显式配置。写回过程会使用 staging 目录,4.0.3 起可以通过 hive.staging_dir 调整临时路径,避免临时目录和目标表位于不同命名空间导致移动失败。

5.2 Iceberg Catalog:开放湖仓的完整表语义
Iceberg Catalog 支持多种元数据服务:
- Hive Metastore;
- Iceberg REST Catalog;
- Hadoop FileSystem Catalog;
- AWS Glue;
- Alibaba DLF;
- Iceberg JDBC Catalog;
- AWS S3 Tables。
Iceberg 的核心是 Snapshot。每次 Append、Overwrite、Update、Delete 或 Merge 都会生成新的表状态。Doris 默认读取最新 Snapshot,也可以使用历史时间或 Snapshot ID:
SELECT *
FROM iceberg_prod.sales.product_dim
FOR TIME AS OF '2026-08-01 10:00:00';
SELECT *
FROM iceberg_prod.sales.product_dim
FOR VERSION AS OF 123456789;
Doris 还支持读取 Branch 和 Tag。3.1.0 起可以管理 Branch/Tag 和 Schema Change;4.1.0 起提供实验性的 Iceberg V3 Row Lineage 隐藏列 _row_id、_last_updated_sequence_number,适合增量同步和审计验证。
当前 Iceberg 写入能力较完整,包括:
INSERT
INSERT OVERWRITE
UPDATE
DELETE
MERGE INTO
CTAS
Schema Change
这使 Doris 可以承担湖仓数据处理引擎角色:读取 Hive 或 JDBC 数据,完成 Join 和聚合,再把结果写入 Iceberg。写回链路需要测试并发提交、Snapshot 增长、Manifest 数量、对象存储请求和失败回滚。

5.3 Hudi Catalog:读取 CDC 沉淀结果
Hudi Catalog 复用 Hive Catalog,通过 HMS 获取表信息,并结合 Hudi Timeline、Meta Client 和文件系统视图完成读取。常见表类型包括:
- Copy-on-Write:读取路径直接,写入侧承担合并成本;
- Merge-on-Read:读取时合并 Base File 和 Log File,适合更高频更新。
Doris 支持普通快照查询、Time Travel 和 Incremental Query。Hudi Time Travel 使用 FOR TIME AS OF,不支持 FOR VERSION AS OF。增量读取可以使用 @incr 指定起止 Commit Time,并在执行计划中转化为对 _hoodie_commit_time 的过滤。
hudi.use_hive_sync_partition=true 可以直接使用 HMS 已同步的分区信息,效率更高;前提是 Hudi 写入任务持续把最新分区同步到 HMS。同步延迟会导致新分区暂时不可见。
当前 Hudi Catalog 支持查询加速和数据入仓,数据写回尚未支持。需要由 Flink 或 Spark 等 Hudi 写入引擎负责外部表更新。
5.4 Paimon Catalog:实时湖仓与变更语义
Paimon Catalog 支持 Filesystem、HMS、DLF 和 JDBC 元数据服务。Paimon JDBC Catalog 从 4.1.0 起提供,当前带有实验属性。
Paimon 查询能力包括:
- 普通 Snapshot 查询;
- Batch Incremental Query;
- Time Travel;
- Branch 和 Tag;
$snapshots、$files、$partitions、$manifests等系统表;@options选择指定 Snapshot、Tag、Watermark 或增量起点。
例如:
SELECT snapshot_id, commit_time
FROM paimon_prod.realtime.events$snapshots;
SELECT *
FROM paimon_prod.realtime.events
FOR VERSION AS OF 12;
Doris 当前对 Paimon 只开放读取能力。需要写入 Paimon 时,继续使用 Flink 或其他原生写入引擎。

5.5 JDBC Catalog:远端小表和按需集成
JDBC Catalog 支持 MySQL、PostgreSQL、Oracle、SQL Server、IBM DB2、ClickHouse、SAP HANA 和 OceanBase。执行链路依赖 Java 和 JDBC Driver,Doris 3.0+ 的 JDK 17 环境能够提供更好的整体性能。
JDBC Catalog 的生产边界需要明确:
- 适合读取客户、组织、配置、汇率、字典等小表;
- 适合把少量源库数据导入 Doris;
- 适合核验和低并发跨源 Join;
- 大表全量扫描会占用源库 CPU、IO、连接和网络;
- Doris 无法改变远端数据库的物理索引和执行能力;
- 下推失败时,可能把大量数据拉到 Doris 再过滤。
生产设计应使用源库只读账号,配置连接超时和 Fetch Size,限制并发,监控源库慢 SQL,并为大表准备 CDC 或批量入仓方案。

六、跨 Catalog 查询怎样执行
以下 SQL 同时访问 Hive 事实表、Iceberg 商品维表和 MySQL 客户维表:
SELECT
h.dt,
h.region,
i.category,
j.level,
SUM(h.amount) AS sales_amount
FROM hive_prod.sales_dw.fact_sales AS h
JOIN iceberg_prod.sales.product_dim AS i
ON h.product_id = i.product_id
JOIN mysql_business.business.customer AS j
ON h.customer_id = j.customer_id
WHERE h.dt >= DATE '2026-08-01'
GROUP BY h.dt, h.region, i.category, j.level;
FE 会分别读取三个 Catalog 的 Schema 和统计信息,判断过滤选择率、Join 顺序、Build/Probe 侧和 Distribution。BE 读取 Hive/Iceberg 文件,并通过 JDBC 获取小维表数据。理想执行计划通常具备以下特征:
- Hive 日期分区完成裁剪;
- 只读取查询涉及的列;
- Parquet/ORC Row Group 或 Iceberg 文件统计继续过滤;
- MySQL 查询带有必要字段和过滤条件;
- 小型 JDBC 维表进入 Broadcast Build 侧;
- Runtime Filter 从维表或聚合 Build 侧下推到大事实表 Scan;
- 最终只传输经过过滤和局部聚合的数据。
跨源 Join 的性能上限由最慢数据源决定。外部存储延迟、JDBC 源库负载、文件数量和元数据请求都可能形成长尾。生产 POC 需要同时保存 Explain、Query Profile 和外部系统监控。
七、外表查询的逐级裁剪
湖仓查询的第一原则是减少远端读取。Doris 可以在多个层级收缩数据范围:
- Catalog/Database 过滤:减少元数据范围;
- Partition Pruning:根据目录或表格式分区信息跳过无关分区;
- Manifest/File Pruning:利用 Iceberg Manifest、文件 Min/Max 等信息过滤文件;
- Row Group/Stripe Pruning:利用 Parquet Row Group 或 ORC Stripe 统计;
- Column Pruning:只读取 SQL 使用的列;
- Predicate Pushdown:在 Scanner 侧执行过滤;
- Runtime Filter:Join 运行时把 Build 侧条件发送给 Probe 侧 Scan;
- Vectorized Execution:使用列式 Block 批量解码和计算。

容易破坏裁剪的写法包括:
WHERE DATE_FORMAT(event_time, '%Y-%m-%d') = '2026-08-01'
更利于下推和分区裁剪的形式是:
WHERE event_time >= '2026-08-01 00:00:00'
AND event_time < '2026-08-02 00:00:00'
文件布局同样重要。数十万个极小 Parquet 文件会增加远端 LIST、文件打开、Footer 读取和调度开销。Doris 查询侧能够并行读取,却无法完全消除上游小文件设计带来的成本。湖仓治理需要在写入引擎侧持续执行文件合并和分区优化。
