From db0ca9eb4083dc96072a5018908fd94bc0f371d4 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 12 Aug 2026 14:03:52 +0100 Subject: [PATCH] fix(webapp): drop unused OrgMember _count aggregate from org-list presenter (#4587) ## What `OrganizationsPresenter.#getOrganizations` selected a Prisma `_count.members` relation on every org-list load (hit on nearly every dashboard navigation). Prisma lowers that relation `_count` to a whole-`OrgMember`-table `GROUP BY organizationId` aggregate joined onto `Organization`. The computed `membersCount` field is read by **nothing** in the webapp, so the entire aggregate scan is wasted work. This removes the `_count` select and the `membersCount` field. The query keeps only the indexed `EXISTS` membership filter and the org/project selects. ## Why it's safe - `membersCount` has zero consumers (whole-webapp grep finds the name only at the point of assignment). It was added in #1796 (2023) and has been unused since. - The member count shown on the org settings/team page comes from a separate presenter query, not this one. No user-visible change. ## Evidence (generated SQL, before/after, seeded isolated stack) Before (with `_count.members`): ```sql SELECT ..., COALESCE(aggr._aggr_count_members, 0) FROM "Organization" LEFT JOIN (SELECT "organizationId", COUNT(*) AS _aggr_count_members FROM "OrgMember" GROUP BY "organizationId") aggr ON ... WHERE EXISTS (... "userId" = $1 ...) AND "deletedAt" IS NULL ORDER BY "createdAt" DESC ``` After: ```sql SELECT id, slug, title, avatar, "featureFlags" FROM "Organization" WHERE EXISTS (... "userId" = $1 ...) AND "deletedAt" IS NULL ORDER BY "createdAt" DESC ``` The whole-table `GROUP BY` aggregate is gone. The only remaining `OrgMember` access is the `EXISTS` on the caller's own membership (indexed by `userId`, a handful of rows). This is the single largest read-amplification query on the control-plane database (~1.39B rows read/day, ~719s DB CPU/day per Insights); removing it takes that portion to zero. Webapp typecheck passes. ## Rollout Straight deploy, zero blast radius. Rollback is a plain revert, no data migration. refs TRI-13170 --- .server-changes/org-list-member-count.md | 6 ++++++ apps/webapp/app/presenters/OrganizationsPresenter.server.ts | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 .server-changes/org-list-member-count.md diff --git a/.server-changes/org-list-member-count.md b/.server-changes/org-list-member-count.md new file mode 100644 index 000000000..638349c0a --- /dev/null +++ b/.server-changes/org-list-member-count.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: improvement +--- + +Reduced database load when loading the dashboard by removing an unused organization member count that was being calculated on every page navigation. diff --git a/apps/webapp/app/presenters/OrganizationsPresenter.server.ts b/apps/webapp/app/presenters/OrganizationsPresenter.server.ts index c002be691..9737ab58d 100644 --- a/apps/webapp/app/presenters/OrganizationsPresenter.server.ts +++ b/apps/webapp/app/presenters/OrganizationsPresenter.server.ts @@ -152,11 +152,6 @@ export class OrganizationsPresenter { }, orderBy: { name: "asc" }, }, - _count: { - select: { - members: true, - }, - }, }, }); @@ -191,7 +186,6 @@ export class OrganizationsPresenter { updatedAt: project.updatedAt, externalRef: project.externalRef, })), - membersCount: org._count.members, }; }); }