You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by "Mryange (via GitHub)" <gi...@apache.org> on 2026/04/20 10:57:52 UTC

[PR] [opt](expr) fast path for format() with constant string pattern [doris]

Mryange opened a new pull request, #62639:
URL: https://github.com/apache/doris/pull/62639

   ## Problem
   
   The current `format()` SQL function calls `fmt::format` (or `fmt::vformat` with a `dynamic_format_arg_store`) **per row**. For each row this incurs:
   
   1. Re-parsing the format string on every call.
   2. Allocating a temporary `fmt::memory_buffer` per row.
   3. Copying the result out into `ColumnString`.
   
   When the format string is a constant expression (the common case in SQL), all three costs are avoidable.
   
   ## Solution
   
   Add a fast path that activates when:
   - The first argument (format pattern) is a `ColumnConst`, **and**
   - All non-format arguments are `String`/`VARCHAR` type, **and**
   - The pattern contains no format-spec characters (`:`) — i.e. only plain `{}` or `{N}` placeholders.
   
   The fast path consists of two stages:
   
   **Stage 1 — parse once** (`parse_format_fast_pattern`): Walk the constant pattern string once, splitting it into a `FastFormatPattern` containing the literal segments between placeholders and the argument index each placeholder resolves to. Returns `std::nullopt` for unsupported patterns (format specs, bad braces, out-of-range indices).
   
   **Stage 2 — single-alloc columnar copy** (`execute_fast_string`): Pre-compute total output size in one pass over the offset arrays, call `resize()` once on `ColumnString::Chars`, then `memcpy` literal segments and argument data directly into the result buffer. No temporary allocations per row.
   
   Patterns not matching the fast path (format specs, numeric args, non-const pattern) fall through unchanged to the existing `fmt::format`/`fmt::vformat` slow path.
   
   ## Benchmark (4096 rows)
   
   | Scenario | Old (µs/iter) | New (µs/iter) | Speedup |
   |---|---:|---:|---:|
   | `format("Greeting: {}!", user)` — 2-arg | 210 | 32 | **6.5x** |
   | `format("{} + {} = {}", a, b, c)` — 3-arg | 380 | 63 | **6.0x** |
   
   
   
   ### Release note
   
   None
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [ ] Regression test
       - [ ] Unit Test
       - [ ] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
   - Behavior changed:
       - [ ] No.
       - [ ] Yes. <!-- Explain the behavior change -->
   
   - Does this need documentation?
       - [ ] No.
       - [ ] Yes. <!-- Add document PR link here. eg: https://github.com/apache/doris-website/pull/1214 -->
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "Mryange (via GitHub)" <gi...@apache.org>.
Mryange commented on PR #62639:
URL: https://github.com/apache/doris/pull/62639#issuecomment-4280056387

   /review


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on code in PR #62639:
URL: https://github.com/apache/doris/pull/62639#discussion_r3110278995


##########
be/src/exprs/function/function_format.cpp:
##########
@@ -33,6 +36,169 @@
 
 namespace doris {
 
+// ---------------------------------------------------------------------------
+// Fast-path helpers for format(const_pattern, string_col...)
+//
+// When the format string is a constant with only plain {} or {N} placeholders
+// (no format spec such as {:>10} or {:.2f}), the result can be assembled by
+// directly memcpy-ing literal substrings and column data into a pre-allocated
+// output buffer — no per-row fmt::format call is needed.
+// ---------------------------------------------------------------------------
+
+// Parsed representation of a format pattern that qualifies for the fast path.
+struct FastFormatPattern {
+    // Literal substrings split by the placeholders.
+    // substrings.size() == indices.size() + 1
+    std::vector<std::string> substrings;
+    // 0-based argument indices for each placeholder (into the arg columns,
+    // not counting the format-string column itself).
+    std::vector<size_t> indices;
+};
+
+// Try to parse `pattern` into a FastFormatPattern.
+// `arg_count` is the number of non-format arguments.
+// Returns nullopt when the pattern is not suitable for the fast path (e.g.
+// it contains a format spec, mismatched braces, or out-of-range indices).
+static std::optional<FastFormatPattern> parse_format_fast_pattern(std::string_view pattern,
+                                                                  size_t arg_count) {
+    FastFormatPattern result;
+    size_t auto_idx = 0;
+    int numbering = -1; // -1=undetermined, 0=auto, 1=manual
+    std::string cur;
+
+    for (size_t i = 0; i < pattern.size(); ++i) {
+        const char c = pattern[i];
+        if (c == '{') {
+            // Escaped {{ → literal '{'
+            if (i + 1 < pattern.size() && pattern[i + 1] == '{') {
+                cur += '{';
+                ++i;
+                continue;
+            }
+            // Scan to closing '}', bail out if ':' (format spec) is found first.
+            size_t j = i + 1;
+            while (j < pattern.size() && pattern[j] != '}' && pattern[j] != ':') {
+                ++j;
+            }
+            if (j >= pattern.size() || pattern[j] == ':') {
+                return std::nullopt;
+            }
+            const std::string_view idx_str = pattern.substr(i + 1, j - i - 1);
+            result.substrings.push_back(std::move(cur));
+            cur.clear();
+
+            size_t arg_idx = 0;
+            if (idx_str.empty()) {
+                // Auto-numbering: {}, {}, ...
+                if (numbering == 1) {
+                    return std::nullopt; // mixed auto + manual
+                }
+                numbering = 0;
+                arg_idx = auto_idx++;
+            } else {
+                // Manual numbering: {0}, {1}, ...
+                if (numbering == 0) {
+                    return std::nullopt; // mixed auto + manual
+                }
+                numbering = 1;

Review Comment:
   This digit loop makes the fast-path parser accept manual indices that `fmt` rejects. In `fmt`'s runtime parser, `0` is only valid as a standalone arg_id, so `{01}` is an invalid format string, and overly large indices are rejected instead of wrapping. Here `idx_str = "01"` becomes index 1, so `select format('{01}', 'a', 'b')` changes from `Invalid Input argument` on the old slow path to returning `b` on the new fast path. Please keep this parser aligned with `fmt::parse_arg_id` semantics or fall back to the slow path for these cases.`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "Mryange (via GitHub)" <gi...@apache.org>.
Mryange closed pull request #62639: [opt](expr) fast path for format() with constant string pattern
URL: https://github.com/apache/doris/pull/62639


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "hello-stephen (via GitHub)" <gi...@apache.org>.
hello-stephen commented on PR #62639:
URL: https://github.com/apache/doris/pull/62639#issuecomment-4280045181

   
   Thank you for your contribution to Apache Doris.
   Don't know what should be done next? See [How to process your PR](https://cwiki.apache.org/confluence/display/DORIS/How+to+process+your+PR).
   
   Please clearly describe your PR:
   1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
   2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
   3. What features were added. Why was this function added?
   4. Which code was refactored and why was this part of the code refactored?
   5. Which functions were optimized and what is the difference before and after the optimization?
       


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "Mryange (via GitHub)" <gi...@apache.org>.
Mryange commented on PR #62639:
URL: https://github.com/apache/doris/pull/62639#issuecomment-4285392237

   run performance


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "Mryange (via GitHub)" <gi...@apache.org>.
Mryange commented on PR #62639:
URL: https://github.com/apache/doris/pull/62639#issuecomment-4280065034

   run buildall


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org


Re: [PR] [opt](expr) fast path for format() with constant string pattern [doris]

Posted by "hello-stephen (via GitHub)" <gi...@apache.org>.
hello-stephen commented on PR #62639:
URL: https://github.com/apache/doris/pull/62639#issuecomment-4280964888

   # BE Regression && UT Coverage Report
   Increment line coverage `90.23% (120/133)` :tada:
   
   [Increment coverage report](http://coverage.selectdb-in.cc/coverage/62639_7ebe1f74efdd06753d4e737e62ddaa700a57c59a_merge/increment_report/index.html)
   [Complete coverage report](http://coverage.selectdb-in.cc/coverage/62639_7ebe1f74efdd06753d4e737e62ddaa700a57c59a_merge/report/index.html)
   | Category          | Coverage           |
   |-------------------|--------------------|
   | Function Coverage | 73.78% (27584/37389) |
   | Line Coverage     | 57.51% (298312/518701) |
   | Region Coverage   | 54.67% (247962/453575) |
   | Branch Coverage   | 56.27% (107365/190794) |


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org