# UNDF: UNDF-2026-000000500
# pinot-0001: SegmentProcessorUtils sortOrder List.contains per field in schema loop

## Severity
MEDIUM

## Location
`pinot-core/src/main/java/org/apache/pinot/core/segment/processing/utils/SegmentProcessorUtils.java:66-67` — `getFieldSpecs()` method

## Pattern
SLOW: `List<String> sortOrder` with `.contains(fieldSpec.getName())` inside `for (FieldSpec : schema.getAllFieldSpecs())` — O(F×S) total
FAST: `Set<String> sortOrderSet = new HashSet<>(sortOrder)` before loop, `.contains()` — O(F) total

## Context

In `getFieldSpecs()`, after processing the sort columns, all schema fields are iterated to classify metrics vs non-metrics. During this loop, each field is checked against `sortOrder` to exclude already-added fields:

```java
for (FieldSpec fieldSpec : schema.getAllFieldSpecs()) {
    if (!fieldSpec.isVirtualColumn() && !sortOrder.contains(fieldSpec.getName())) {
```

`sortOrder` is a `List<String>` passed as a parameter. `List.contains()` is O(S) where S = sort order length. For F total fields, total complexity is O(F×S).

`getFieldSpecs()` is called during segment creation/merge operations (CONCAT, ROLLUP, DEDUP merge types). For a schema with F=500 fields and S=20 sort columns, this is 10,000 string comparisons instead of 500. This runs once per segment merge, and in large ingestion pipelines with thousands of concurrent tasks, this cost accumulates.

## Speedup
20× at F=500 fields, S=20 sort columns (typical high-cardinality OLAP table)

## Patch
```diff
--- a/pinot-core/src/main/java/org/apache/pinot/core/segment/processing/utils/SegmentProcessorUtils.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/segment/processing/utils/SegmentProcessorUtils.java
@@ -62,8 +62,10 @@ public class SegmentProcessorUtils {
     }

     List<FieldSpec> metricFieldSpecs = new ArrayList<>();
     List<FieldSpec> nonMetricFieldSpecs = new ArrayList<>();
+    Set<String> sortOrderSet = new HashSet<>(sortOrder);
     for (FieldSpec fieldSpec : schema.getAllFieldSpecs()) {
-      if (!fieldSpec.isVirtualColumn() && !sortOrder.contains(fieldSpec.getName())) {
+      if (!fieldSpec.isVirtualColumn() && !sortOrderSet.contains(fieldSpec.getName())) {
         if (fieldSpec.getFieldType() == FieldSpec.FieldType.METRIC) {
           metricFieldSpecs.add(fieldSpec);
         } else {
```
