Repository navigation
feat: make the dictionary size cap configurable and raise its default to 2 MiB - #10766
XiangpengHao wants to merge 1 commit into
Conversation
… to 2 MiB A dictionary closes once its values reach `max_bytes` before compression. At 1 MiB, high-cardinality string columns close one every few tens of thousands of rows, so each column's bytes are laid out in runs of a few hundred KiB between other columns' segments, and a scan of one column with object-store coalescing also reads the segments in between. Raise the default to 2 MiB, and let `WriteStrategyBuilder` set it with `with_dict_max_bytes`. Signed-off-by: Xiangpeng Hao <xiangpeng@spiraldb.com>
Merging this PR will improve performance by 23.13%4 warnings, 1 note
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
Summary
DictStrategycloses a dictionary once its values reach 1 MiB before compression, and the default write strategy has no way to change that. High-cardinality string columns reach the cap every few tens of thousands of rows. In the file, each such column is laid out in runs of about one dictionary (its values and its codes), with other columns' segments in between. WithCoalesceConfig::object_storage()(1 MiB gap, 16 MiB max), a scan of one of these columns merges across the gaps and reads the other columns' segments too.This raises the default cap to 2 MiB and lets
WriteStrategyBuilderset it. On ClickBench'shits_0(1M rows), converted from Parquet with the default write strategy once with each cap:The file shrinks from 96.5 MB to 92.5 MB (−4.2%), and from 788 to 656 segments, since repeated strings are stored in fewer dictionaries. The scan figures are computed from the footer's segment map with the object-storage window, not measured from queries.
The cost is reads of a few rows: they fetch and decode a dictionary about twice as large. For URL, one row needs about 731 KiB of codes and values, up from 383 KiB. Writers who care more about point reads can keep 1 MiB with
with_dict_max_bytes.Changes
DictLayoutConstraints::default()setsmax_bytesto 2 MiB, up from 1 MiB. Its doc now says the cap is measured on the values before compression, and that the remaining rows start a new dictionary.WriteStrategyBuilder::with_dict_max_bytessets the cap for the default write strategy, which used to always pass the default constraints.API Changes
WriteStrategyBuilder::with_dict_max_bytes.No new tests. Builds, clippy and tests were not run locally.