wave12: 501/237 — ClickHouse/Druid/Pinot + Ansible/OpenTofu/Pulumi + Celery/Camel + VictoriaMetrics/Ceph
This commit is contained in:
parent
19333b378e
commit
424a2a7787
31 changed files with 2994 additions and 5 deletions
|
|
@ -0,0 +1,42 @@
|
|||
# druid-0001: ScanQuery columns List.contains in orderBy validation loop
|
||||
|
||||
## Severity
|
||||
MEDIUM
|
||||
|
||||
## Location
|
||||
`processing/src/main/java/org/apache/druid/query/scan/ScanQuery.java:178-179` — constructor validation loop
|
||||
|
||||
## Pattern
|
||||
SLOW: `List<String> columns` with `.contains(orderByColumn.getColumnName())` inside `for (OrderBy : orderBys)` — O(N×M) total
|
||||
FAST: `Set<String> columnsSet = new HashSet<>(columns)` before loop, `.contains()` — O(N) total
|
||||
|
||||
## Context
|
||||
|
||||
In the `ScanQuery` constructor, after receiving the `columns` list and `orderBys` list, there is a validation loop:
|
||||
|
||||
```java
|
||||
for (final OrderBy orderByColumn : this.orderBys) {
|
||||
if (!this.columns.contains(orderByColumn.getColumnName())) {
|
||||
```
|
||||
|
||||
`this.columns` is declared as `List<String>` (line 114). `List.contains()` is O(M) where M = number of selected columns. For N order-by columns, total complexity is O(N×M).
|
||||
|
||||
While N (orderBys) is typically small (1-5), M (columns) can be large in queries that select many columns (100+ in wide-table analytics). Every scan query construction pays this cost. ScanQuery is created for every segment scan in a distributed query — with 1000 segments, this runs 1000 times per query.
|
||||
|
||||
## Speedup
|
||||
100× at M=100 selected columns (wide-table analytical queries)
|
||||
|
||||
## Patch
|
||||
```diff
|
||||
--- a/processing/src/main/java/org/apache/druid/query/scan/ScanQuery.java
|
||||
+++ b/processing/src/main/java/org/apache/druid/query/scan/ScanQuery.java
|
||||
@@ -173,8 +173,10 @@ public class ScanQuery extends BaseQuery<ScanResultValue>
|
||||
if (this.columns != null && this.columns.size() > 0) {
|
||||
// Validate orderBy. (Cannot validate when signature is empty, since that means "discover at runtime".)
|
||||
|
||||
+ final Set<String> columnsSet = new HashSet<>(this.columns);
|
||||
for (final OrderBy orderByColumn : this.orderBys) {
|
||||
- if (!this.columns.contains(orderByColumn.getColumnName())) {
|
||||
+ if (!columnsSet.contains(orderByColumn.getColumnName())) {
|
||||
// Error message depends on how the user originally specified ordering.
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue