Skip to content

Add indexes on sp_action.rollout and rollout_group#3045

Open
clayly wants to merge 1 commit intoeclipse-hawkbit:masterfrom
clayly:perf/sp-action-rollout-indexes
Open

Add indexes on sp_action.rollout and rollout_group#3045
clayly wants to merge 1 commit intoeclipse-hawkbit:masterfrom
clayly:perf/sp-action-rollout-indexes

Conversation

@clayly
Copy link
Copy Markdown
Contributor

@clayly clayly commented May 2, 2026

Summary

Several rollout-monitoring queries on sp_action (existsByRolloutId, getStatusCountByRolloutId, getStatusCountByRolloutGroupId, etc.) filter by rollout or rollout_group. The flyway baseline does not index either column, so Postgres falls back to Seq Scan, scanning the entire sp_action table on every monitoring poll.

For a 16 k-device rollout this means 16 k action rows scanned per call, multiple times per second during dispatch and monitoring. Beyond a single rollout, the table grows over the lifetime of the deployment and the cost grows linearly.

Fix

Two composite indexes:

  • sp_idx_action_rollout_status on (tenant, rollout, status) — covers both filter and GROUP BY status patterns; enables Index Only Scan with no heap fetch
  • sp_idx_action_rollout_group on (tenant, rollout_group) — covers rollout_group=? lookups (Hibernate-generated SQL always includes tenant via the multi-tenant filter)

V1_20_2__action_rollout_indexes migrations added for POSTGRESQL, H2, and MYSQL.

Idempotency

Each migration is guarded so re-applying the SQL against a schema that already has the index is a no-op:

  • PostgreSQL and H2: CREATE INDEX IF NOT EXISTS
  • MySQL ≤ 8.x has no native IF NOT EXISTS for CREATE INDEX, so the migration uses an INFORMATION_SCHEMA lookup with PREPARE/EXECUTE. MariaDB and MySQL behave identically here.

This protects deployments that may already have created these indexes out-of-band (e.g. via a fork's repeatable migration, an operator hot-fix, or a re-run after a failed migration).

Performance evidence

Insert 16 000 rows into sp_action tied to rollout=1, spread across rollout_group=1..17. Run the hot queries 1000 times each, before and after the indexes.

PostgreSQL 16

query no index with index speedup
WHERE tenant=? AND rollout=? GROUP BY status 1.256 s 0.504 s 2.5x
WHERE tenant=? AND rollout_group=? count 0.501 s 0.027 s 18.6x
WHERE rollout=? LIMIT 1 (exists) 1.5 µs 1.4 µs 1x (early-out)

Plans switch from Seq Scan to Index Only Scan, Heap Fetches: 0. Buffer reads drop from 214 → 17 (12x).

YugabyteDB (PostgreSQL-compatible YSQL)

query no index with index speedup
WHERE tenant=? AND rollout=? GROUP BY status 4.146 s 2.841 s 1.5x
WHERE tenant=? AND rollout_group=? count 2.595 s 0.148 s 17.6x
WHERE rollout=? LIMIT 1 (exists) 21 µs 21 µs 1x (early-out)

Plain PG syntax works on YB. The leading column gets HASH-partitioned across tablets by default, optimal for the equality-on-tenant access pattern. Index Only Scan is supported on YB with Heap Fetches: 0.

YB seq scans are 3–5x slower than PG seq scans (network round-trip per page across tablets), so the index is even more critical on a YugabyteDB deployment.

Test plan

  • Schema migration applies cleanly on H2, PostgreSQL and YugabyteDB
  • Re-applying migration against a schema that already has the indexes is a no-op
  • EXPLAIN confirms Index Only Scan after migration
  • Long-running rollout test (1 k+ targets) before/after — measure UI rollout-detail responsiveness

@hawkbit-bot
Copy link
Copy Markdown

Thanks @clayly for taking the time to contribute to hawkBit! We really appreciate this. Make yourself comfortable while I'm looking for a committer to help you with your contribution.
Please make sure you read the contribution guide and signed the Eclipse Contributor Agreement (ECA).

Rollout monitoring queries (existsByRolloutId, getStatusCountByRolloutId,
getStatusCountByRolloutGroupId) filter by rollout or rollout_group on
sp_action. The flyway baseline did not index either column, so Postgres
falls back to Seq Scan on every monitoring poll. With 16k action rows
this is meaningful — the group-count query takes ~500 ms without the
index and ~27 ms with it (Index Only Scan, Heap Fetches: 0).

Bench (16k rows, 1000 iter):
- WHERE tenant=? AND rollout_group=?           18.6x faster on PG
                                               17.6x faster on YugabyteDB
- WHERE tenant=? AND rollout=? GROUP BY status  2.5x faster on PG
                                                1.5x faster on YugabyteDB

Adds V1_20_2 sibling migrations for POSTGRESQL, H2, and MYSQL.
@clayly clayly force-pushed the perf/sp-action-rollout-indexes branch from 83390ff to 51c1316 Compare May 3, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants