Skip to content

perf(rls): wrap auth.uid() in the account policies so it evaluates once per statement - #106

Open
dmitrymaranik wants to merge 1 commit into
usebasejump:mainfrom
dmitrymaranik:perf/wrap-rls-initplan
Open

perf(rls): wrap auth.uid() in the account policies so it evaluates once per statement#106
dmitrymaranik wants to merge 1 commit into
usebasejump:mainfrom
dmitrymaranik:perf/wrap-rls-initplan

Conversation

@dmitrymaranik

Copy link
Copy Markdown

What

Two of the account RLS policies in supabase/migrations/20240414161947_basejump-accounts.sql call auth.uid() directly in their USING clause:

  • "users can view their own account_users"user_id = auth.uid()
  • "Accounts are viewable by primary owner"primary_owner_user_id = auth.uid()

Left unwrapped, Postgres re-evaluates auth.uid() once per row scanned — it can't tell the call is constant across the statement — on two of the hottest read paths (account_user and accounts).

Fix

Wrap the call in a scalar sub-select so the planner hoists it to a one-time InitPlan (once per statement instead of once per row):

using ( user_id = (select auth.uid()) )
using ( primary_owner_user_id = (select auth.uid()) )

auth.uid() is constant within a statement, so the value is identical — same rows, fewer calls. This is the pattern Supabase documents for auth.*() in policies, and since Basejump is a widely-forked template, every project that scaffolds from it inherits the fix.

Scope / what's deliberately not changed

Only the two directly row-independent auth.uid() calls are wrapped. The other policies gate on basejump.has_role_on_account(account_id, …), which takes the row's account_id as an argument — that's genuinely row-dependent and must be evaluated per row, so wrapping it would be incorrect. Left untouched.

Surfaced by pgrls (PERF001), an open-source Postgres RLS linter / verifier. I couldn't run the Supabase test suite locally, but the change is value-preserving (a pure planner hint).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant