From fa87b86f3affb5dc878d41d6d287188f86d73340 Mon Sep 17 00:00:00 2001 From: John Coffey Date: Thu, 8 Oct 2026 15:59:14 -0700 Subject: [PATCH] Prepare search deletions without caching them The index task deletes a batch of documents with one `docid = $n` term per document, so every batch shape is new SQL text. The connection's statement cache has no limit and kept each of them, on both sides, for the life of the connection. Deletions are maintenance; they are now prepared for the one use, and the statement is closed after it. --- crates/store/src/backend/postgres/search.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/store/src/backend/postgres/search.rs b/crates/store/src/backend/postgres/search.rs index 56161e5d..c172ce98 100644 --- a/crates/store/src/backend/postgres/search.rs +++ b/crates/store/src/backend/postgres/search.rs @@ -244,8 +244,14 @@ impl PostgresStore { let conn = self.conn_pool.get().await.map_err(into_pool_error)?; let limit = self.timeouts.maintenance; let result = tokio::time::timeout(limit, async { + // inbuxa: prepared, not cached. The index task deletes a batch + // with one `docid = $n` term per document, so each batch shape + // is new SQL text, and the per-connection statement cache (no + // limit) kept every one of them for the life of the connection, + // on both sides. A deletion is maintenance; the extra round + // trip to prepare is nothing next to it. let s = conn - .prepare_cached(&format!("DELETE FROM {table}{where_clause}")) + .prepare(&format!("DELETE FROM {table}{where_clause}")) .await .map_err(into_error)?; @@ -260,7 +266,7 @@ impl PostgresStore { loop { let s = conn - .prepare_cached(&format!( + .prepare(&format!( "DELETE FROM {table} WHERE ctid IN (SELECT ctid FROM {table}{where_clause} LIMIT {chunk_size})" )) .await -- 2.54.0