fix(catalog-backend): use INNER JOIN for filtered entity facets
Replace the `WHERE search.entity_id IN (...)` form with an INNER JOIN against the filtered final_entities subquery in DefaultEntitiesCatalog#facets. Results are unchanged; the planner gets more freedom to pick cheaper plans, which on large catalogs leads to substantial speedups (1.2× to 7×+ in adversarial testing on a ~13.8M-row search table) and avoids the materialize-then-spill pattern of the IN form. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Fredrik Adelöw <freben@spotify.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Improved the performance of the entity facets endpoint when filters are applied. The filtered entity set is now combined with the search table through an inner join rather than a `WHERE entity_id IN (subquery)`. Results are unchanged; on large catalogs the query planner is able to choose dramatically cheaper plans, with measured improvements ranging from roughly 1.2× on already-fast cases to 7× or more on high-cardinality facets.
|
||||
@@ -707,7 +707,17 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog {
|
||||
knex: this.database,
|
||||
});
|
||||
|
||||
query.whereIn('search.entity_id', entityIdSubquery);
|
||||
// Use INNER JOIN rather than `WHERE search.entity_id IN (...)`. The
|
||||
// results are the same but the JOIN form gives the planner more
|
||||
// freedom in join shape and ordering. On PostgreSQL with large
|
||||
// search tables, the IN form tends to materialize the full filtered
|
||||
// entity set up front and spill to temp; the JOIN form lets the
|
||||
// planner pick a much cheaper plan based on actual selectivities.
|
||||
query.innerJoin(
|
||||
entityIdSubquery.as('filtered_entities'),
|
||||
'search.entity_id',
|
||||
'filtered_entities.entity_id',
|
||||
);
|
||||
}
|
||||
|
||||
const rows = await query;
|
||||
|
||||
Reference in New Issue
Block a user