vibesql_executor/select/join/search/config.rs
1//! Configuration for join order search
2
3#![allow(clippy::unnecessary_literal_unwrap)]
4
5/// Configuration for parallel join order search
6#[derive(Debug, Clone)]
7pub struct ParallelSearchConfig {
8 /// Enable parallel BFS search (vs sequential DFS)
9 pub enabled: bool,
10 /// Maximum depth to explore with parallel BFS (tables with >max_depth use DFS)
11 pub max_depth: usize,
12 /// Maximum states per layer before pruning
13 pub max_states_per_layer: usize,
14 /// Prune states with cost > best * threshold
15 pub pruning_threshold: f64,
16 /// Maximum time budget for join order search (milliseconds)
17 /// Default: 1000ms for OLAP workloads
18 pub time_budget_ms: u64,
19 /// Whether to use time-bounded search (vs table-count cutoff)
20 pub use_time_budget: bool,
21 /// Enable verbose logging of search statistics
22 pub verbose: bool,
23}
24
25impl Default for ParallelSearchConfig {
26 fn default() -> Self {
27 Self::with_table_count(4) // Default assumes 4 tables
28 }
29}
30
31impl ParallelSearchConfig {
32 /// Create a config with adaptive time budget based on table count
33 ///
34 /// The time budget increases with query complexity:
35 /// - 1-3 tables: 500ms (simple queries)
36 /// - 4-5 tables: 1000ms (typical OLAP queries)
37 /// - 6-7 tables: 1500ms (complex multi-way joins like Q7)
38 /// - 8+ tables: 2000ms (very complex queries like Q21)
39 ///
40 /// This adaptive approach gives more time to complex queries that need it
41 /// while keeping simple queries fast.
42 pub fn with_table_count(num_tables: usize) -> Self {
43 // Read time budget from environment variable if set (overrides adaptive)
44 let time_budget_ms = std::env::var("JOIN_REORDER_TIME_BUDGET_MS")
45 .ok()
46 .and_then(|s| s.parse().ok())
47 .unwrap_or({
48 // Adaptive budget based on table count
49 match num_tables {
50 0..=3 => 500, // Simple queries
51 4..=5 => 1000, // Typical OLAP
52 6..=7 => 1500, // Complex multi-way joins (Q7)
53 _ => 2000, // Very complex (Q21)
54 }
55 });
56
57 let verbose = std::env::var("JOIN_REORDER_VERBOSE").is_ok();
58
59 Self {
60 enabled: true,
61 max_depth: 8, // Support 8-way joins like TPC-H Q8
62 max_states_per_layer: 1000,
63 pruning_threshold: 1.5,
64 time_budget_ms,
65 use_time_budget: true, // New: prefer time-bounded over table-count
66 verbose,
67 }
68 }
69}