用户指南

Crate 配置

qianmoQqianmoQ· 更新于 2026-09-29· 阅读 16 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

Crate 配置

本节介绍如何在 Rust 项目中配置 DataFusion 的构建。配置设置一节列出了可控制 DataFusion 运行时行为其他方面的选项。

使用每夜构建的 DataFusion

DataFusion 的变更会按照发布流程发布到 crates.io。

如果你想使用或测试那些已经合并但尚未发布的 DataFusion 代码版本,可以利用 Cargo 的添加依赖项功能,直接指向某个 GitHub 分支:

datafusion = { git = "https://github.com/apache/datafusion", branch = "main"}

此外,它在包级别同样有效。

datafusion-common = { git = "https://github.com/apache/datafusion", branch = "main", package = "datafusion-common"}

以及功能特性

datafusion = { git = "https://github.com/apache/datafusion", branch = "main", default-features = false, features = ["unicode_expressions"] }

更多内容参见 Cargo 依赖

优化构建

以下是几条建议,可让 Rust 编译器在编译 DataFusion 时生成更快的代码。请注意,这些改动可能会增加编译时间和二进制文件大小。

使用针对 CPU 的特定指令生成代码

默认情况下,Rust 编译器生成的代码可在多种 CPU 上运行,但可能无法利用你所使用 CPU 的全部特性(例如某些 SIMD 指令)。对于 x86_64 CPU 尤其如此,其默认目标是 x86_64-unknown-linux-gnu,该目标仅保证支持 SSE2 指令集。DataFusion 可以从 AVX2 和 AVX512 中更高级的指令中获益,从而加速过滤、聚合和连接等操作。要让 Rust 编译器使用这些指令,请设置 RUSTFLAGS 环境变量以指定更具体的 target CPU。

我们建议设置 target-cpu,或者至少设置 avx2,更好的做法是至少设置为 native(即当前 CPU 的型号)。例如,要针对当前 CPU 进行优化来构建并运行 DataFusion:

RUSTFLAGS='-C target-cpu=native' cargo run --release

启用链接时优化 / 单一代码生成单元

通过将 DataFusion 编译为单一代码生成单元,你有可能提升性能,这使 Rust 编译器有更多机会跨越 crate 边界进行优化。为此,请按如下所示修改项目的 Cargo.toml,加入 lto = true 和 codegen-units = 1。请注意,使用单一代码生成单元会显著增加 --release 构建所需的时间。

[profile.release]
lto = true
codegen-units = 1

剖析引导优化(PGO)

剖析引导优化(Profile Guided Optimization)可以将 DataFusion 的性能提升多达 25%。其工作方式是:先以插桩方式编译,运行具有代表性的工作负载以收集剖析数据,然后基于这些数据重新编译以进行优化。

使用插桩进行构建:

RUSTFLAGS="-C profile-generate=/tmp/pgo-data" cargo build --release

运行你的工作负载以收集性能剖析数据。可以使用 TPCH 或 Clickbench 等基准测试,也可以使用你实际的生产查询:

./target/release/your-datafusion-app --benchmark

使用收集到的 profile 重新构建:

RUSTFLAGS="-C profile-use=/tmp/pgo-data" cargo build --release

提示:

  • 使用与生产环境模式相匹配的工作负载
  • 在性能分析期间多次运行,以获得更好的覆盖范围
  • 结合 LTO 与针对特定 CPU 的优化,以获得最佳效果

更多详情请参阅 Rust 编译器指南。相关的讨论与结果见 issue devlive-community/knowforge#9507。

替代分配器:snmalloc

你也可以使用 snmalloc-rs crate 作为 DataFusion 的内存分配器,以提升性能。具体做法是按照如下所示在 Cargo.toml 中添加该依赖。

[dependencies]
snmalloc-rs = "0.3"

然后,在 main.rs 中,于导入语句之后加入以下内容以更新内存分配器:

use datafusion::prelude::*;

#[global_allocator]
static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc;

#[tokio::main]
async fn main() -> datafusion::error::Result<()> {
  Ok(())
}

启用回溯

默认情况下,DataFusion 只会返回纯文本形式的错误信息。如果你想获取更详细的错误信息(例如回溯信息),可以在 Cargo.toml 文件中启用 backtrace 特性,方式如下:

datafusion = { version = "55.1.0", features = ["backtrace"]}

设置环境变量

RUST_BACKTRACE=1 ./target/debug/datafusion-cli
DataFusion CLI v31.0.0
> select row_numer() over (partition by a order by a) from (select 1 a);
Error during planning: Invalid function 'row_numer'.
Did you mean 'ROW_NUMBER'?

backtrace:    0: std::backtrace_rs::backtrace::libunwind::trace
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2: std::backtrace::Backtrace::create
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/std/src/backtrace.rs:332:13
   3: std::backtrace::Backtrace::capture
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/std/src/backtrace.rs:298:9
   4: datafusion_common::error::DataFusionError::get_back_trace
             at /datafusion/datafusion/common/src/error.rs:436:30
   5: datafusion_sql::expr::function::<impl datafusion_sql::planner::SqlToRel<S>>::sql_function_to_expr
   ............

回溯信息在调试代码时非常有用。如果 datafusion/core/src/physical_planner.rs 中有一个测试

#[tokio::test]
async fn test_get_backtrace_for_failed_code() -> Result<()> {
    let ctx = SessionContext::new();

    let sql = "
    select row_numer() over (partition by a order by a) from (select 1 a);
    ";

    let _ = ctx.sql(sql).await?.collect().await?;

    Ok(())
}

要获取回溯信息:

cargo build --features=backtrace
RUST_BACKTRACE=1 cargo test --features=backtrace --package datafusion --lib -- physical_planner::tests::test_get_backtrace_for_failed_code --exact --nocapture

running 1 test
Error: Plan("Invalid function 'row_numer'.\nDid you mean 'ROW_NUMBER'?\n\nbacktrace:    0: std::backtrace_rs::backtrace::libunwind::trace\n             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5\n   1: std::backtrace_rs::backtrace::trace_unsynchronized\n...

注意:回溯信息会被截断到系统调用处,因此回溯顶部的某些步骤可以忽略。

若要以美化打印的格式显示回溯信息,请使用 eprintln!("{e}");。

#[tokio::test]
async fn test_get_backtrace_for_failed_code() -> Result<()> {
    let ctx = SessionContext::new();

    let sql = "select row_numer() over (partition by a order by a) from (select 1 a);";

    let _ = match ctx.sql(sql).await {
        Ok(result) => result.show().await?,
        Err(e) => {
            eprintln!("{e}");
        }
    };

    Ok(())
}

然后运行测试:

$ RUST_BACKTRACE=1 cargo test --features=backtrace --package datafusion --lib -- physical_planner::tests::test_get_backtrace_for_failed_code --exact --nocapture

running 1 test
Error during planning: Invalid function 'row_numer'.
Did you mean 'ROW_NUMBER'?

backtrace:    0: std::backtrace_rs::backtrace::libunwind::trace
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2: std::backtrace::Backtrace::create
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/backtrace.rs:331:13
   3: std::backtrace::Backtrace::capture
   ...

评论

登录后参与评论

正在加载评论…