# UNDF: UNDF-2026-000000396
# flink-0003: AggregateReduceGroupingRule — List<Integer>.contains() inside for loop

## Defect ID
flink-0003

## File:Line
`flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/plan/rules/logical/AggregateReduceGroupingRule.java:88`

## Description
In `onMatch()`:

```java
List<Integer> newGroupingList = newGrouping.toList();  // List<Integer>
for (int column : originalGrouping) {                  // O(G) iterations
    if (newGroupingList.contains(column)) {            // O(G) linear scan each time
        ...
    }
}
```

`newGroupingList` is a `List<Integer>`. Each `.contains()` call does a linear scan
O(G) where G = number of grouping columns. Total: O(G²).

This fires during query planning on every aggregate that has reducible grouping keys —
i.e., every GROUP BY with functional dependencies. In queries with wide GROUP BY
clauses (e.g., 50+ columns in analytics), this is O(2500) instead of O(50).

## Complexity
- Slow: O(G²) — List.contains() = O(G)
- Fast: O(G) — HashSet.contains() = O(1)

## Severity
MEDIUM

## Speedup Estimate
~G× improvement; at G=50 grouping columns, ~50x speedup in the planning phase.

## Fix
Replace `newGroupingList` with `Set<Integer> newGroupingSet = new HashSet<>(newGrouping.toList())`.
The list is only used for `.contains()` and `.size()` — both work identically on HashSet.
