Epic: Cost-Based Dictionary Encoding
- Dominant language
- Rust
- Stars
- 9.3k
- Forks
- 2.4k
- Avg merge
- 3d 7h
- Merged PRs (30d)
- 344
Description
### Is your feature request related to a problem or challenge?
Aggregating over low-cardinality string columns (e.g. GROUP BY on category/status-like fields) is slower than it needs to be, because DataFusion has no way to represent these as dictionary-encoded arrays automatically. Today, getting the performance benefit requires manually casting columns yourself, there's no config to opt in, no way to bound it by cardinality, and no mechanism for the engine to decide this on its own based on the data or query shape.
### Describe the solution you'd like
- [ ] #24112
- [ ] #24113
- [x] #22891
- [ ] #24114
- [ ] #24116
- [ ] #24117
Together these give users manual control first (enable dictionary reads, set a cardinality threshold), then build the statistics and optimizer support needed for DataFusion to make that same decision automatically. The end goal is a physical plan optimization that casts low-cardinality string columns to dictionary arrays before aggregation when the stats justify it, without requiring any manual intervention.
**Currently**
```
SELECT
gender,
shirt_size,
marital_status,
region,
count(*) AS cnt,
sum(amount) AS total_amount,
avg(amount) AS avg_amount,
min(amount) AS min_amount,
max(amount) AS max_amount
FROM orders
GROUP BY gender, shirt_size, marital_status, region
ORDER BY gender, shirt_size, marital_status, region;
```
With 20 million rows, we'd repeatedly process the same string data over and over, even though Parquet metadata could tell us up front that these columns are low cardinality (gender: 2, shirt_size: 4, marital_status: 2, region: 10)
once this epic is complete we'd have something like
```
SET datafusion.parquet.dict_read_enable = true
SET datafusion.parquet.dict_threshold = .05
SELECT
gender,
shirt_size,
marital_status,
region,
count(*) AS cnt,
sum(amount) AS total_amount,
avg(amount) AS avg_amount,
min(amount) AS min_amount,
max(amount) AS max_amount
FROM orders
GROUP BY gender, shirt_size, marital_status, region
ORDER BY gender, shirt_size, marital_status, region;
```
with [dictionary arrays being supported directly ](https://github.com/apache/datafusion/pull/23187) in the aggregation pipeline this would be much more efficient. [example](https://github.com/apache/datafusion/pull/23187#issuecomment-5193826956)
Related issues
- [X] https://github.com/apache/datafusion/issues/23993
- [ ] https://github.com/apache/datafusion/issues/24089
- [ ] https://github.com/apache/datafusion/pull/25185
- [ ] https://github.com/apache/datafusion/issues/23127
- [x] #23921
- [x] https://github.com/apache/arrow-rs/issues/10590
- [x] https://github.com/apache/arrow-rs/pull/10765
- [x] https://github.com/apache/arrow-rs/issues/10830
- [x] https://github.com/apache/arrow-rs/issues/10650
### Additional context
https://github.com/apache/datafusion/pull/23187#issuecomment-5190571128
https://github.com/apache/datafusion/pull/23187#issuecomment-5192617111
Contributor guide
Research direction
Start by reading the linked child issues (#24112, #24113, #22891, #24114, #24116, and #24117) and the referenced dictionary-array aggregation pull request #23187. Done means completing the checklist so DataFusion can use statistics and query shape to choose dictionary encoding automatically before aggregation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sql
- Domain
- databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100