perf(schemas): index organization_user_relations on (tenant_id, user_id)#8818
Merged
simeng-li merged 1 commit intoMay 18, 2026
Conversation
COMPARE TO
|
| Name | Diff |
|---|---|
| .changeset/index-organization-user-relations-user-id.md | 📈 +505 Bytes |
| .gitignore | 📈 +18 Bytes |
| packages/schemas/alterations/next-1778500000-add-organization-user-relations-user-id-index.ts | 📈 +1.58 KB |
| packages/schemas/tables/organization_user_relations.sql | 📈 +116 Bytes |
e3d20bd to
30d74dd
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a secondary DB index to improve performance of organization membership reverse lookups (by tenant_id + user_id) that are on the hot path for sign-in/token exchange and membership checks.
Changes:
- Add a new schema alteration to create
(tenant_id, user_id)index onorganization_user_relations. - Add a changeset bumping
@logto/schemasas a patch release.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/schemas/alterations/next-1778500000-add-organization-user-relations-user-id-index.ts | Adds an alteration to create/drop the new secondary index for (tenant_id, user_id) lookups. |
| .changeset/index-organization-user-relations-user-id.md | Publishes the schema change via a Changeset patch release note for @logto/schemas. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
30d74dd to
44a9e9e
Compare
4 tasks
The primary key on organization_user_relations is (tenant_id, organization_id, user_id), which prevents queries that filter by user_id without specifying organization_id from using the index. getOrganizationsByUserId (called on every sign-in) and the membership- existence middleware on /organizations/:id/users/:userId/roles endpoints both fall through to a partial scan today. The FK constraint organization_user_relations__user_id__fk added in 1.30.0 references users (tenant_id, id) and indexes only the referenced side; Postgres does not auto-index the referencing side. The new index is added to both the alteration script (for existing databases) and the table source file (for fresh installs), matching the pattern of the prior FK alteration on the same table. Refs LOG-13472
44a9e9e to
33f35a6
Compare
wangsijie
approved these changes
May 17, 2026
gao-sun
approved these changes
May 18, 2026
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refs LOG-13472. First task in the Phase 0.5 performance milestone surfaced by the audit before LOG-13462 lands.
What changed
packages/schemas/alterations/next-1778500000-add-organization-user-relations-user-id-index.ts— new migration that addscreate index concurrently if not exists organization_user_relations__tenant_id_user_id on organization_user_relations (tenant_id, user_id). Builtconcurrentlyvia thebeforeUphook so no table lock is held during the build. Reversible viabeforeDownrunningdrop index concurrently if exists.packages/schemas/tables/organization_user_relations.sql— mirrors the new index inline so fresh installs get it without replaying the alteration..changeset/index-organization-user-relations-user-id.md—@logto/schemaspatch.Expected result
(tenant_id, user_id)without specifyingorganization_idswitch from a partial PK scan to anIndex Scanon the new secondary index. The two hot call sites this fixes:getOrganizationsByUserId(packages/core/src/queries/organization/user-relations.ts:78-99) — runs on every token exchange / sign-in / org-list endpoint./organizations/:id/users/:userId/rolesand/users/:userId/scopes(packages/core/src/utils/RelationQueries.ts:249-265invoked fromroutes/organization/user/role-relations.ts:34).Reviewer notes
(tenant_id, organization_id, user_id)does not serveuser_id-only lookups, so they currently degrade. The FK constraint added in1.30.0-1753669579-add-organization-user-relations-foreign-key.tsonly indexes the referenced side (users (tenant_id, id)) — Postgres does not auto-index the referencing side.beforeUp/beforeDownnon-transactional hooks soCONCURRENTLYcan be used without holding the write-blockingSHARElock that a plainCREATE INDEXwould hold for the duration of the build. This matches the pattern in1.35.0-1765183934-add-logs-created-at-id-index.ts,1.35.0-1765631949-drop-redundant-logs-id-index.ts, and1.38.0-1772615848-add-oidc-model-instances-grant-id-partial-index.ts.if not exists/if existskeep both directions idempotent against transient failures.<table>__<columns>convention. Confirmed unique via grep.Testing
Tested locally
Checklist
.changeset