From 52c32bee4e48b8361707dd94272db0376c661556 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 11 Jun 2026 11:12:59 +0200 Subject: [PATCH] fix(storage): index triggers_occurrences(trigger_id, date) Migration 8 dropped the (trigger_id, event_id) primary key in favour of (id), leaving trigger_id unindexed. ListTriggersOccurrences filters WHERE trigger_id = ? ordered by date, so every page was a sequential scan over an ever-growing table. Add a migration creating the composite index, built CONCURRENTLY (the migrator runs each migration on a dedicated non-transactional connection) and IF NOT EXISTS for idempotency. --- internal/storage/migrations.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/storage/migrations.go b/internal/storage/migrations.go index 33ff453..144cb53 100644 --- a/internal/storage/migrations.go +++ b/internal/storage/migrations.go @@ -172,6 +172,22 @@ var _migrations = []migrations.Migration{ return nil }, }, + { + // Migration 8 dropped the (trigger_id, event_id) primary key in favour + // of (id), leaving trigger_id unindexed. ListTriggersOccurrences filters + // WHERE trigger_id = ? and orders by date, so without this index every + // page is a sequential scan over an ever-growing table. Built + // CONCURRENTLY to avoid blocking writes during deploy. + Up: func(ctx context.Context, tx bun.IDB) error { + if _, err := tx.ExecContext(ctx, ` + create index concurrently if not exists triggers_occurrences_trigger_id_date_idx + on triggers_occurrences (trigger_id, date); + `); err != nil { + return err + } + return nil + }, + }, } func Migrate(ctx context.Context, db *bun.DB) error {