基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Doris 在进行外部 Catalog 数据湖联邦查询时,采用了哪些缓存和下推优化手段(如元数据缓存、Filter 下推、向量化读取外表等)来提高外表查询性能?

Apache Doris 在进行外部 Catalog(如 Hive、Iceberg、Hudi、Delta Lake、JDBC 等)数据湖联邦查询时,为了解决网络 I/O 瓶颈、元数据获取延迟以及 CPU 计算瓶颈,设计了一套多维度、深度的优化体系

以下是 Doris 提高外表查询性能所采用的核心优化手段,主要分为元数据层、下推优化、向量化引擎与 IO、数据缓存四个方面:


一、 元数据缓存与裁剪(Metadata Caching & Pruning)

在联邦查询中,获取外表元数据(如 Schema、分区信息、文件列表)往往会带来高延迟(比如频繁请求 Hive Metastore 或 HDFS/S3)。Doris 引入了多级元数据缓存机制:

  1. 元数据多级缓存(Multi-Level Metadata Cache)
    • Schema 缓存:缓存外表的表结构,避免每次查询都去拉取。
    • Partition 缓存:缓存分区列表信息。
    • File 缓存:缓存每个分区下的具体文件列表(File List)及文件块(Split)信息。Doris 会在 FE(Frontend)中缓存这些信息,极大减少了与外部 Metastore 和存储系统的交互频率。
    • 自动/手动刷新:支持 TTL(生存时间)自动失效、手动 REFRESH CATALOG,以及通过外表事件监听(如 HMS Event Listener)实现元数据增量自动同步。
  2. 分区裁剪(Partition Pruning)
    • 在 FE 执行规划时,根据 SQL 中的分区过滤条件,提前过滤掉不相关的分区,避免对底层存储(如 HDFS/S3)进行全量文件扫描。

二、 极速下推优化(Pushdown Optimizations)

下推是减少数据传输量和计算量最有效的手段。Doris 实现了深度的算子下推:

  1. 谓词下推(Filter Pushdown)
    • 引擎层下推:将 WHERE 条件下推至外表存储格式层。对于 Parquet 和 ORC 格式,Doris 能够利用文件自带的统计信息(Page-level / Stripe-level Min/Max、Null Count 等)在读取时直接过滤掉不满足条件的数据块。
    • 源端下推:对于 JDBC Catalog,Doris 会将过滤条件直接拼接到生成的 SQL 中,在关系型数据库端完成过滤。
  2. 列投影下推(Projection Pushdown / Column Pruning)
    • 只读取 SQL 中声明的列,对于宽表查询,这能减少 80% 以上的 I/O。对于 Parquet/ORC 等列式存储,效果极其显著。
  3. Limit/Top-N 下推
    • LIMIT 算子下推到 Scan 节点。在读取到足够的数据后立即停止 Scan,避免读取无用文件。
  4. Runtime Filter 下推(动态过滤器)
    • 这是 Doris 联邦查询的一大杀器。在进行外表与内表(或外表与外表)的 Join 查询时,Doris 会在 Hash 构建端(通常是小表/内表)动态生成 Runtime Filter(如 Min/Max、Bloom Filter、In Filter),并将其推送到外表(大表)的 Scan 节点
    • 外表在从 HDFS/S3 读取数据时,直接利用这个过滤条件对行进行过滤,甚至可以在 Parquet/ORC 索引层直接过滤,极大减少了网络传输和后续的 Join 计算。

三、 向量化读取与执行(Vectorized Engine & Native Reader)

Doris 拥有纯 C++ 实现的向量化执行引擎,在外表读取上也做到了“原生化”:

  1. 自研 C++ Native Reader(原生外表读取器)
    • Doris 摒弃了传统的 Java API(JNI)读取方式,针对 Parquet 和 ORC 格式用 C++ 重写了高性能 Reader
    • 通过自研 Reader,数据可以直接从文件系统加载到 Doris 的向量化内存结构(Block)中,避免了 JVM 与 C++ 之间的内存拷贝和 JNI 调用开销,性能提升数倍。
  2. 延迟物化(Late Materialization / Lazy Materialization)
    • 在读取 Parquet/ORC 列时,Doris 会先读取带有过滤条件的列(比如 age > 18 中的 age 列),在内存中进行过滤,确定保留的行号(Row ID)后,再去延迟读取其他投影列。这避免了读取那些最终会被过滤掉的行的数据。
  3. 字典解密优化(Dictionary Decoding)
    • 对于 Parquet 等编码格式,Doris 尽量在字典编码状态下进行过滤和传输,直到最后一步才进行真正的解码(Decoding),节省了 CPU 算力。

四、 数据缓存机制(Data Cache / File Cache)

为了解决远端存储(如 S3、OSS、HDFS)网络带宽瓶颈和高延迟,Doris 提供了内置的 File Cache(文件缓存)

  1. 本地 Block 级缓存
    • Doris BE 节点可以配置本地高速介质(如 SSD)作为缓存盘。当首次读取远端数据湖中的 Parquet/ORC 文件时,Doris 会将文件切分为 Block 并缓存到本地。
    • 后续相同的查询或对该数据的查询,将直接命中本地 SSD 缓存,使外表查询达到接近内表的极速性能。
  2. 一致性哈希路由(Consistent Hash Client-side Routing)
    • 为了提高缓存命中率,Doris 在分布式扫描时采用一致性哈希算法,确保同一个文件块(Split)的读取任务尽量分配给同一个 BE 节点,从而最大化本地缓存的复用率。

五、 CBO 基于代价的优化器(Optimizer Support)

Doris 的 CBO(Cost-Based Optimizer)同样适用于外表:

  1. 外表统计信息收集(Statistics)
    • Doris 支持通过 ANALYZE 命令收集外表(如 Hive/Iceberg)的统计信息(如 Row Count、Null Count、Min/Max、NDV)。对于 Iceberg 等自身保存了丰富元数据信息的格式,Doris 可以直接读取其元数据来填充优化器。
  2. Join Reorder
    • 有了统计信息后,CBO 可以准确估算外表 Join 的代价,自动选择最优的 Join 顺序和 Join 类型(Shuffle Join, Broadcast Join 或 Bucket Shuffle Join),避免产生灾难性的笛卡尔积。

总结

Doris 在联邦查询上的优化思路是:能不读就不读(元数据缓存、分区裁剪、列裁剪、延迟物化),能少读就少读(谓词/Runtime Filter下推、本地数据缓存),读的时候要极速(C++ Native 向量化读取)。通过这一整套组合拳,Doris 在数据湖分析场景下展现出了极强的竞争力。

00:00
00:00