Is your feature request related to a problem? Please describe.
On iModels without federation guids (or with forceExternalSourceAspectProvenance), provenance is tracked through ExternalSourceAspects, and the transformer issues one ECSQL lookup per entity: queryScopeExternalSourceAspect per exported element and relationship, plus per-deleted-entity queries in processDeletedOp (queryProvenanceForElement/queryProvenanceForRelationship and an inline Element.Id → Identifier lookup). All of these scan the same scope's aspects one row at a time.
Describe the solution you'd like
Lazily build one in-memory index per ESA Kind (Element/Relationship) from a single scope-wide query against the provenance db (getProvenanceDb(), so reverse sync resolves correctly), then serve the hot-path lookups from that index. The index must stay consistent with in-run inserts/updates/deletes, preserve the previous LIMIT-1 first-match semantics for non-unique Identifiers (merged elements), and be memory-bounded with fallback to per-row queries above a configurable threshold. The public static queryScopeExternalSourceAspect stays unchanged.
Describe alternatives you've considered
Eagerly building the index at transformation start (rejected — wasted work for fedguid-based transforms that never query ESAs); caching inside the static query method (rejected — no lifecycle to invalidate against, and external callers expect live queries).
Additional context
Implemented in #391 (~5% median improvement on the quick perf suite's incremental-synchronization scenario, whose fixture lacks fedguids on 19/20 elements); bounded via IMODEL_TRANSFORMER_MAX_ESA_CACHE_SIZE (default 4M rows per Kind). See the PR for results and details.
generated with Claude Fable 5
Is your feature request related to a problem? Please describe.
On iModels without federation guids (or with
forceExternalSourceAspectProvenance), provenance is tracked through ExternalSourceAspects, and the transformer issues one ECSQL lookup per entity:queryScopeExternalSourceAspectper exported element and relationship, plus per-deleted-entity queries inprocessDeletedOp(queryProvenanceForElement/queryProvenanceForRelationshipand an inlineElement.Id → Identifierlookup). All of these scan the same scope's aspects one row at a time.Describe the solution you'd like
Lazily build one in-memory index per ESA Kind (Element/Relationship) from a single scope-wide query against the provenance db (
getProvenanceDb(), so reverse sync resolves correctly), then serve the hot-path lookups from that index. The index must stay consistent with in-run inserts/updates/deletes, preserve the previous LIMIT-1 first-match semantics for non-unique Identifiers (merged elements), and be memory-bounded with fallback to per-row queries above a configurable threshold. The public staticqueryScopeExternalSourceAspectstays unchanged.Describe alternatives you've considered
Eagerly building the index at transformation start (rejected — wasted work for fedguid-based transforms that never query ESAs); caching inside the static query method (rejected — no lifecycle to invalidate against, and external callers expect live queries).
Additional context
Implemented in #391 (~5% median improvement on the quick perf suite's
incremental-synchronizationscenario, whose fixture lacks fedguids on 19/20 elements); bounded viaIMODEL_TRANSFORMER_MAX_ESA_CACHE_SIZE(default 4M rows per Kind). See the PR for results and details.generated with Claude Fable 5