From d263d260dcc0addb868b4d6eedd9c2675490b2d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 02:48:34 +0000 Subject: [PATCH 1/4] Initial plan From 603683d3484518b5f0cc473046e69fb412e5257f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 03:07:48 +0000 Subject: [PATCH 2/4] Optimize inefficient code patterns for better performance - Replace += &format!() with write!() macro in format.rs to avoid unnecessary allocations - Replace += with push_str() for string literals in parser/error.rs - Add Vec::with_capacity in kv_pb_api for pre-allocated vectors - Optimize u64 formatting in key_builder.rs to write directly to buffer Co-authored-by: sundy-li <3325189+sundy-li@users.noreply.github.com> --- src/meta/api/src/kv_pb_api/mod.rs | 10 +++-- src/meta/kvapi/src/kvapi/key_builder.rs | 13 ++++++- src/query/ast/src/parser/error.rs | 12 +++--- src/query/sql/src/executor/format.rs | 49 ++++++++++++++++--------- 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/meta/api/src/kv_pb_api/mod.rs b/src/meta/api/src/kv_pb_api/mod.rs index f577b60be5a0e..f582ab5c52976 100644 --- a/src/meta/api/src/kv_pb_api/mod.rs +++ b/src/meta/api/src/kv_pb_api/mod.rs @@ -212,14 +212,15 @@ pub trait KVPbApi: KVApi { Self::Error: From>, { let it = keys.into_iter(); - let key_chunks = it + let key_chunks: Vec> = it .chunks(Self::CHUNK_SIZE) .into_iter() .map(|x| x.collect::>()) .collect::>(); + let total_keys: usize = key_chunks.iter().map(|c| c.len()).sum(); async move { - let mut res = vec![]; + let mut res = Vec::with_capacity(total_keys); for chunk in key_chunks { let strm = self.get_pb_values(chunk).await?; @@ -278,14 +279,15 @@ pub trait KVPbApi: KVApi { Self::Error: From>, { let it = keys.into_iter(); - let key_chunks = it + let key_chunks: Vec> = it .chunks(Self::CHUNK_SIZE) .into_iter() .map(|x| x.collect::>()) .collect::>(); + let total_keys: usize = key_chunks.iter().map(|c| c.len()).sum(); async move { - let mut res = vec![]; + let mut res = Vec::with_capacity(total_keys); for chunk in key_chunks { let strm = self.get_pb_stream(chunk).await?; diff --git a/src/meta/kvapi/src/kvapi/key_builder.rs b/src/meta/kvapi/src/kvapi/key_builder.rs index 8fe6b26c8b694..3a2f3dad00575 100644 --- a/src/meta/kvapi/src/kvapi/key_builder.rs +++ b/src/meta/kvapi/src/kvapi/key_builder.rs @@ -46,8 +46,17 @@ impl KeyBuilder { self.push_raw(&escape(s)) } - pub fn push_u64(self, n: u64) -> Self { - self.push_raw(&format!("{}", n)) + pub fn push_u64(mut self, n: u64) -> Self { + use std::io::Write; + + if !self.buf.is_empty() { + // `/` + self.buf.push(0x2f); + } + + // Write directly to buffer instead of allocating a string + write!(self.buf, "{}", n).unwrap(); + self } pub fn done(self) -> String { diff --git a/src/query/ast/src/parser/error.rs b/src/query/ast/src/parser/error.rs index 4837424dbc172..8c3d0617deca8 100644 --- a/src/query/ast/src/parser/error.rs +++ b/src/query/ast/src/parser/error.rs @@ -255,7 +255,7 @@ pub fn display_parser_error(error: Error, source: &str) -> String { format!("unexpected `{span_text}`") }; if let Some(suggestion) = has_suggestion { - msg += &format!(". {}", suggestion); + write!(msg, ". {}", suggestion).unwrap(); labels = vec![(inner.span, msg)]; // Return early to skip context labels when we have intelligent suggestions @@ -270,15 +270,15 @@ pub fn display_parser_error(error: Error, source: &str) -> String { write!(msg, ", or {} more ...", more).unwrap(); break; } else if i == 0 { - msg += ", expecting "; + msg.push_str(", expecting "); } else if iter.peek().is_none() && i == 1 { - msg += " or "; + msg.push_str(" or "); } else if iter.peek().is_none() { - msg += ", or "; + msg.push_str(", or "); } else { - msg += ", "; + msg.push_str(", "); } - msg += error; + msg.push_str(error); } labels = vec![(inner.span, msg)]; diff --git a/src/query/sql/src/executor/format.rs b/src/query/sql/src/executor/format.rs index a7aaf9acaafbf..25161c75a41c1 100644 --- a/src/query/sql/src/executor/format.rs +++ b/src/query/sql/src/executor/format.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::collections::HashMap; +use std::fmt::Write; use databend_common_ast::ast::FormatTreeNode; use databend_common_base::base::format_byte_size; @@ -1788,59 +1789,69 @@ fn part_stats_info_to_format_tree(info: &PartStatistics) -> Vec 0 { - blocks_pruning_description += &format!( + write!( + blocks_pruning_description, "range pruning: {} to {}", info.pruning_stats.blocks_range_pruning_before, info.pruning_stats.blocks_range_pruning_after - ); + ) + .unwrap(); } // bloom pruning status. if info.pruning_stats.blocks_bloom_pruning_before > 0 { if !blocks_pruning_description.is_empty() { - blocks_pruning_description += ", "; + blocks_pruning_description.push_str(", "); } - blocks_pruning_description += &format!( + write!( + blocks_pruning_description, "bloom pruning: {} to {}", info.pruning_stats.blocks_bloom_pruning_before, info.pruning_stats.blocks_bloom_pruning_after - ); + ) + .unwrap(); } // inverted index pruning status. if info.pruning_stats.blocks_inverted_index_pruning_before > 0 { if !blocks_pruning_description.is_empty() { - blocks_pruning_description += ", "; + blocks_pruning_description.push_str(", "); } - blocks_pruning_description += &format!( + write!( + blocks_pruning_description, "inverted pruning: {} to {}", info.pruning_stats.blocks_inverted_index_pruning_before, info.pruning_stats.blocks_inverted_index_pruning_after - ); + ) + .unwrap(); } // topn pruning status. if info.pruning_stats.blocks_topn_pruning_before > 0 { if !blocks_pruning_description.is_empty() { - blocks_pruning_description += ", "; + blocks_pruning_description.push_str(", "); } - blocks_pruning_description += &format!( + write!( + blocks_pruning_description, "topn pruning: {} to {}", info.pruning_stats.blocks_topn_pruning_before, info.pruning_stats.blocks_topn_pruning_after - ); + ) + .unwrap(); } // vector index pruning status. if info.pruning_stats.blocks_vector_index_pruning_before > 0 { if !blocks_pruning_description.is_empty() { - blocks_pruning_description += ", "; + blocks_pruning_description.push_str(", "); } - blocks_pruning_description += &format!( + write!( + blocks_pruning_description, "vector pruning: {} to {}", info.pruning_stats.blocks_vector_index_pruning_before, info.pruning_stats.blocks_vector_index_pruning_after - ); + ) + .unwrap(); } // Combine segment pruning and blocks pruning descriptions if any @@ -1850,18 +1861,20 @@ fn part_stats_info_to_format_tree(info: &PartStatistics) -> Vec 0 { - pruning_description += &format!( + write!( + pruning_description, "segments: ", info.pruning_stats.segments_range_pruning_before, info.pruning_stats.segments_range_pruning_after - ); + ) + .unwrap(); } if !blocks_pruning_description.is_empty() { if !pruning_description.is_empty() { - pruning_description += ", "; + pruning_description.push_str(", "); } - pruning_description += &format!("blocks: <{}>", blocks_pruning_description); + write!(pruning_description, "blocks: <{}>", blocks_pruning_description).unwrap(); } items.push(FormatTreeNode::new(format!( From 5d087921329b601e7fab5ed0f078a4291f1d9250 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 03:18:23 +0000 Subject: [PATCH 3/4] Fix: use correct Write trait for Vec buffer Move std::io::Write import inside the function to avoid trait conflicts Co-authored-by: sundy-li <3325189+sundy-li@users.noreply.github.com> --- src/meta/kvapi/src/kvapi/key_builder.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/meta/kvapi/src/kvapi/key_builder.rs b/src/meta/kvapi/src/kvapi/key_builder.rs index 3a2f3dad00575..953aaf9800717 100644 --- a/src/meta/kvapi/src/kvapi/key_builder.rs +++ b/src/meta/kvapi/src/kvapi/key_builder.rs @@ -47,14 +47,13 @@ impl KeyBuilder { } pub fn push_u64(mut self, n: u64) -> Self { - use std::io::Write; - if !self.buf.is_empty() { // `/` self.buf.push(0x2f); } // Write directly to buffer instead of allocating a string + use std::io::Write; write!(self.buf, "{}", n).unwrap(); self } From 870e1f0c1eda19dba168d43dda6dad06097d4d77 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 03:20:18 +0000 Subject: [PATCH 4/4] Refactor: move std::io::Write import to top of file Improve code organization by placing imports at the module level Co-authored-by: sundy-li <3325189+sundy-li@users.noreply.github.com> --- src/meta/kvapi/src/kvapi/key_builder.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/meta/kvapi/src/kvapi/key_builder.rs b/src/meta/kvapi/src/kvapi/key_builder.rs index 953aaf9800717..dd30255634e98 100644 --- a/src/meta/kvapi/src/kvapi/key_builder.rs +++ b/src/meta/kvapi/src/kvapi/key_builder.rs @@ -14,6 +14,8 @@ //! A helper for building a string key from a structured key +use std::io::Write; + use crate::kvapi::helper::escape; use crate::kvapi::helper::escape_specified; @@ -53,7 +55,6 @@ impl KeyBuilder { } // Write directly to buffer instead of allocating a string - use std::io::Write; write!(self.buf, "{}", n).unwrap(); self }