commit 6ff22a49f409d7559f66d8ff3dbe1d2f5c299452
parent 08fcf789302c6fd8914481da027ed60200440e3f
Author: triesap <tyson@radroots.org>
Date: Sat, 6 Jun 2026 02:57:42 -0700
bench: add query plan capture
Diffstat:
1 file changed, 58 insertions(+), 0 deletions(-)
diff --git a/crates/tangle_bench/src/lib.rs b/crates/tangle_bench/src/lib.rs
@@ -356,6 +356,52 @@ pub async fn run_search_benchmark(
})
}
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct QueryPlanCaptureReport {
+ pub listing_plan_steps: u64,
+ pub search_plan_steps: u64,
+ pub listing_plan_text: String,
+ pub search_plan_text: String,
+}
+
+pub async fn capture_query_plans(
+ config: BenchDatasetConfig,
+) -> Result<QueryPlanCaptureReport, String> {
+ let dataset = BenchDataset::generate(config)?;
+ let materialized = materialize_listing_workload(&dataset).await?;
+ for event in dataset.listings() {
+ materialized
+ .store()
+ .index_listing_search_document(event)
+ .await
+ .map_err(|error| error.to_string())?;
+ }
+ let listing_query = "SELECT * FROM listing_current WHERE hidden = false AND deleted = false AND effective_status = 'active' ORDER BY updated_at DESC, event_id ASC LIMIT 10 EXPLAIN;";
+ let search_query = "SELECT * FROM search_doc WHERE doc_type = 'listing' AND visible = true ORDER BY updated_at DESC, event_id ASC LIMIT 10 EXPLAIN;";
+ let listing_plan = explain_query(materialized.store(), listing_query).await?;
+ let search_plan = explain_query(materialized.store(), search_query).await?;
+ Ok(QueryPlanCaptureReport {
+ listing_plan_steps: listing_plan.len() as u64,
+ search_plan_steps: search_plan.len() as u64,
+ listing_plan_text: format!("{listing_query}\n{listing_plan:?}"),
+ search_plan_text: format!("{search_query}\n{search_plan:?}"),
+ })
+}
+
+async fn explain_query(
+ store: &SurrealStore,
+ query: &str,
+) -> Result<Vec<serde_json::Value>, String> {
+ let mut response = store
+ .database()
+ .query(query)
+ .await
+ .map_err(|error| error.to_string())?
+ .check()
+ .map_err(|error| error.to_string())?;
+ response.take(0).map_err(|error| error.to_string())
+}
+
async fn bench_memory_store(database: &str) -> Result<SurrealStore, String> {
let config = SurrealConnectionConfig::memory("tangle_bench", database)
.map_err(|error| error.to_string())?;
@@ -576,4 +622,16 @@ mod tests {
assert_eq!(report.browse_results, 9);
assert!(report.elapsed_micros > 0);
}
+
+ #[tokio::test]
+ async fn query_plan_capture_records_listing_and_search_plans() {
+ let report = super::capture_query_plans(BenchDatasetConfig::new(4, 0))
+ .await
+ .expect("query plan capture");
+
+ assert!(report.listing_plan_steps > 0);
+ assert!(report.search_plan_steps > 0);
+ assert!(report.listing_plan_text.contains("listing_current"));
+ assert!(report.search_plan_text.contains("search_doc"));
+ }
}