Uh oh!
There was an error while loading. Please reload this page.
branch-4.0: [opt](csv reader) optimize nullable string deserialization in CSV/text load hot path #64476 - #65844
Conversation
…t load hot path (apache#64476) Issue Number: close #xxx Related PR: apache#60920 (previous attempt, superseded by this stateless implementation) Problem Summary: When loading CSV data, every column is read as a nullable string, so `_deserialize_nullable_string` is the per-row per-column hot path (ClickBench: 105 columns x 100M rows = ~10.5 billion cells). Flame graph shows two major per-cell overheads: 1. `assert_cast<ColumnNullable&>` performs a typeid comparison per cell in release builds. 2. `DataTypeStringSerDe::deserialize_one_cell_from_csv` adds a call layer with another per-cell `assert_cast<ColumnString&>` inside, plus Status plumbing. Its fill-null-on-failure branch is dead code since the method never fails. 1. Use `assert_cast<..., TypeCheckOnRelease::DISABLE>` in `CsvReader::_deserialize_nullable_string` and `TextReader::_deserialize_nullable_string`, which compiles to a plain `static_cast` in release builds. Debug builds still verify the cast. 2. Write the string column and null map directly instead of going through the SerDe layer (semantically identical, verified against `ColumnNullable::insert_data` / `DataTypeStringSerDe` implementations). The virtual `_deserialize_nullable_string` dispatch is kept, so TextReader's hive-text semantics (different escape handling and null detection) remain intact. 3. Add `_reserve_nullable_string_columns`, called once per batch: it performs checked `assert_cast`s (backing the unchecked per-row casts with a real type validation per batch, throwing instead of UB on mismatch) and reserves offsets/null_map capacity to avoid incremental PODArray growth in the row loop. The implementation is stateless: no cached column pointers, no per-batch member state to initialize/clear. A/B test on full ClickBench dataset (73GB / 100M rows / 105 columns), identical deployment and config, only the BE binary differs: | Metric | Before | After | Improvement | |---|---|---|---| | Total load time (BE LoadTime) | 636.6s | 530.9s | -16.6% (1.20x) | | CSV parse (ReadDataTime) | 590.6s | 484.5s | -18.0% | | Avg throughput | 115 MB/s | 138 MB/s | +20% | All 10 splits (10M rows each) improved consistently by 14-18% with small variance. Loaded row counts are identical between the two runs (99,997,497 rows).
hello-stephen
commented
Jul 21, 2026
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
There was a problem hiding this comment.
Pull request overview
Optimizes the CSV and Hive-text load “nullable string” deserialization hot path by bypassing the DataTypeStringSerDe call layer and per-cell checked casts, while preserving the same escaping semantics and reserving per-batch capacity to reduce reallocation churn.
Changes:
- Inlines
DataTypeStringSerDe::deserialize_one_cell_from_csv/hive_textlogic (escape +insert_data) into the hot-path nullable-string deserializers. - Adds a per-batch
_reserve_nullable_string_columns(...)step to do one-time checked casts and reserve offsets/null-map capacity. - Switches per-row casts in hot paths to
TypeCheckOnRelease::DISABLEafter the per-batch verification.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| be/src/vec/exec/format/text/text_reader.cpp | Inlines hive-text nullable string deserialization to avoid SerDe overhead and per-cell checked casts. |
| be/src/vec/exec/format/csv/csv_reader.h | Declares _reserve_nullable_string_columns helper for per-batch verification/reservation. |
| be/src/vec/exec/format/csv/csv_reader.cpp | Adds per-batch reservation + inlines CSV nullable string deserialization to reduce overhead in the per-row/per-column loop. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
liaoxin01
commented
Jul 21, 2026
run buildall |
hello-stephen
commented
Jul 21, 2026
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
Pick #64476