Replace the window-function full-table scan with a two-phase approach
that leverages search_key_value_entity_idx (key, value, entity_id):
Phase 1: GROUP BY entity_id, key, value with HAVING COUNT(*) > 1
resolves as a pure index-only scan (Heap Fetches: 0).
Stores only the duplicate groups in a temp table (~8s for
a 14M-row table with 700k dupes).
Phase 2: CROSS JOIN LATERAL back into search using the same covering
index (Nested Loop + Index Scan). row_number() runs per-group
over the 2-3 matching rows, so there is no global external
sort. A single DELETE removes all extras in one statement
(~16s).
NULL values get a separate UNION ALL arm so the index equality
condition stays usable (value = NULL is always false in SQL).
Benchmarked on a 14.4M-row production-like staging master with
700k injected duplicates, post-VACUUM:
Old (seq scan + external merge sort): ~101s
New (index-only + index scan): ~25s (~4× faster)
Clean second run (no dupes, fast path skips dedup): <50ms.
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Backstage is a single-page application composed of a set of plugins. This folder holds numerous plugins that are managed by this repository. However, most plugins are in the community plugins repo - hop over there if you want to contribute!
For more information about the plugin ecosystem, see the documentation here:
You can also see the Plugin Marketplace for other open source plugins you can add to your Backstage instance.
Suggesting a plugin
If you start developing a plugin that you aim to release as open source, we suggest that you create a new Issue on the community plugins repo. This helps the community know what plugins are in development.
You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work.