Skip to main content
This feature requires StarTree release 0.16.0 or later, and must be enabled on demand — contact StarTree support to activate it.
An External Table sync run creates one Pinot segment per source Parquet file. Iceberg tables with many small files can therefore produce a very large number of segments, each with its own ZooKeeper znode, ideal-state entry, and per-segment metadata — driving up cluster metadata overhead and controller/server memory even though the underlying data volume hasn’t grown. Segment groups let the controller and servers treat a batch of small member segments as one logical unit end-to-end, cutting per-file metadata overhead without changing how you query the table.

How it works

  • A group is a set of member segments (each still a real Parquet-backed segment) tracked and loaded together as one unit by the controller, broker, and servers.
  • Groups are formed automatically by a periodic controller task, sized by row/segment count within a time bucket you configure.
  • Once formed, a group’s membership doesn’t change — segment groups are immutable after creation.
  • Iceberg-sourced External Tables can also be born directly into a group at ingestion time, skipping the standalone-segment step entirely (see Grouping at ingestion time).

Enabling segment groups

Segment groups require an opt-in at both the cluster and table level.

Cluster-level gate

Table-level config

Set under tableConfig.tableCustomConfig.customConfigs.segmentGroupConfig as a JSON string:
Segment groups are not supported for upsert, dedup, or dimension tables in this release — the controller rejects enabled=true for these table types.

Controller task tuning

Two periodic controller tasks drive grouping and lineage cleanup:

Grouping at ingestion time

For Iceberg External Tables synced with executor=controller (see Best Practices & Configs), member segments can be born directly into a group during ingestion instead of first landing as standalone segments and being grouped afterward. This path is snapshot-scoped and immutable, and is managed independently of the periodic SegmentGroupingTask — the grouping task explicitly skips tables using ingestion-time grouping.
Ingestion-time grouping only applies when the External Table Sync task is configured with executor=controller. The legacy minion-distributed sync path does not support it.

Deletion and lifecycle

A member segment’s underlying Parquet file in deep store is only deleted once it has no live standalone segment znode and is not referenced by any live group — deleting an individual member early is unsafe if other members still reference shared state. Group lifecycle operations (load, refresh, delete) are isolated per member, so a failure loading one member doesn’t fail the whole group, and re-registering an already-registered group is idempotent.

FAQs

Do I need to change how I query a table with segment groups enabled?

No. Segment groups are an internal metadata/storage optimization — queries, schemas, and results are unaffected.

Can I disable segment groups after enabling them?

Set segmentGroupConfig.enabled=false and/or pinot.cluster.segment.groups.enabled=false to stop forming new groups. Existing groups are not automatically un-grouped.

Why was my table rejected when I tried to enable segment groups?

Check that the cluster-level gate pinot.cluster.segment.groups.enabled is true, and that the table is not an upsert, dedup, or dimension table — these are unsupported in this release.