Compute MR approver-id set once instead of per rule
What does this MR do and why?
On merge requests with many approval rules, the set of users who have approved was recalculated separately for every rule, issuing the same database query once per rule. This set is the same for all rules on a merge request.
This MR computes it once per merge request and reuses the result across all rules, removing the redundant per-rule queries.
Contributes to https://gitlab.com/gitlab-org/gitlab/-/issues/602716
Benchmark results
Measured on a local GDK against a synthetic project (spike-593394/codeowners-bench)
with MRs of 100 / 400 / 800 code-owner rules. The benchmark exercises the
model-layer widget read (approval_state aggregates + iterating
wrapped_approval_rules and resolving approved? / approvals_required /
approvals_left / invalid_rule?, which trigger overall_approver_ids), with
reset_approval_cache! between iterations to mimic separate requests.
"Without" is clean master; "With" is this MR.
Note: this MR isolates a single fix. Wall time is dominated by an unrelated per-rule CODEOWNERS re-parse (addressed in a separate MR), so the signal here is the query count, which becomes independent of rule count.
approvals.user_id pluck count (the targeted N+1)
| Scenario | Rules | Without | With |
|---|---|---|---|
| small | 100 | 100 | 1 |
| medium | 400 | 400 | 1 |
| large | 800 | 800 | 1 |
The pluck is now flat (1) regardless of rule count — the N+1 is eliminated.
Total non-cached SQL queries (model widget read)
| Scenario | Rules | Without | With | Reduction |
|---|---|---|---|---|
| small | 100 | 205 | 106 | −99 |
| medium | 400 | 805 | 406 | −399 |
| large | 800 | 1606 | 807 | −799 |
(The remaining per-rule protected_branches query is addressed in a separate MR;
this change removes the approvals.user_id pluck N+1.)
How to set up and validate locally
- On a project with
code_owner_approval_required = trueand a large CODEOWNERS file, open a merge request that triggers many code-owner approval rules. - Query
approvalState { rules { approved approvalsRequired } }for that MR and observe the SQL query count (count ofSELECT DISTINCT ... approvals.user_id). - Run the model specs:
bundle exec rspec ee/spec/models/approval_wrapped_rule_spec.rb(85 examples, 0 failures).
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.