From 7ee4972f0e74e5473cf6c78652b4a1f702320cba Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 16 Oct 2026 12:44:57 +0100 Subject: [PATCH] feat(bench): support EXPLAIN ANALYZE in SQL benchmark binaries Expose actual query-plan cardinalities and timings in the DataFusion and DuckDB benchmark runners. Signed-off-by: Joe Isaacs --- benchmarks/datafusion-bench/src/main.rs | 16 +++++++++++++++- benchmarks/duckdb-bench/src/main.rs | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/benchmarks/datafusion-bench/src/main.rs b/benchmarks/datafusion-bench/src/main.rs index 55f2a03fd08..6528ae86af0 100644 --- a/benchmarks/datafusion-bench/src/main.rs +++ b/benchmarks/datafusion-bench/src/main.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::borrow::Cow; use std::path::PathBuf; use std::sync::Arc; use std::time::Instant; @@ -110,6 +111,10 @@ struct Args { #[arg(long, default_value_t = false)] explain: bool, + /// Execute explained queries and include actual operator cardinalities and timings. + #[arg(long, requires = "explain")] + explain_analyze: bool, + /// Print the selected query indices, one per line, and exit /// Knowledge of query ids lies only in this binary so we need /// orchestrator to know whan queries to run one by one. @@ -165,6 +170,7 @@ async fn main() -> anyhow::Result<()> { let collected_plans: Arc)>>> = Arc::new(Mutex::new(Vec::new())); let show_metrics = args.show_metrics; + let explain_analyze = args.explain_analyze; let mode = if args.explain { BenchmarkMode::Explain @@ -197,8 +203,16 @@ async fn main() -> anyhow::Result<()> { Box::pin( async move { + let query = if explain_analyze { + Cow::Owned(format!( + "EXPLAIN ANALYZE {}", + query.strip_prefix("EXPLAIN ").unwrap_or(query) + )) + } else { + Cow::Borrowed(query) + }; let timer = Instant::now(); - let (batches, plan) = execute_query(session, query) + let (batches, plan) = execute_query(session, &query) .with_labelset(get_labelset_from_global()) .await?; let time = timer.elapsed(); diff --git a/benchmarks/duckdb-bench/src/main.rs b/benchmarks/duckdb-bench/src/main.rs index c680d62f836..49af096d319 100644 --- a/benchmarks/duckdb-bench/src/main.rs +++ b/benchmarks/duckdb-bench/src/main.rs @@ -3,6 +3,7 @@ mod validation; +use std::borrow::Cow; use std::path::PathBuf; use clap::Parser; @@ -88,6 +89,10 @@ struct Args { #[arg(long, default_value_t = false)] explain: bool, + /// Execute explained queries and include actual operator cardinalities and timings. + #[arg(long, requires = "explain")] + explain_analyze: bool, + /// Print the selected query indices, one per line, and exit /// Knowledge of query ids lies only in this binary so we need /// orchestrator to know whan queries to run one by one. @@ -222,7 +227,15 @@ fn main() -> anyhow::Result<()> { if !args.reuse { ctx.reopen()?; } - ctx.execute_query_result(query) + let query = if args.explain_analyze { + Cow::Owned(format!( + "EXPLAIN ANALYZE {}", + query.strip_prefix("EXPLAIN ").unwrap_or(query) + )) + } else { + Cow::Borrowed(query) + }; + ctx.execute_query_result(&query) }, )?;