Optimize queries in MergeRequestsComplianceFinder
What does this MR do?
This MR tries to optimize the queries inside MergeRequestsComplianceFinder
class.
Changes:
- Adds missing associations that are required for
preload
. - Tries to make the "LATERAL" query more readable (while maintaining the same logic)
- Prevents loading of all MRs into memory at once, which were then later paginated using
Kaminari.paginate_array
. The pagination is now done at database level itself using the normalLIMIT OFFSET
approach, which helps limit the no of MRs loaded into memory.
Queries
Old query (with lateral) - this gets only events, we had to fetch MRs again using a new query:
explain SELECT projects.id, events.target_id as merge_request_id FROM (SELECT "projects".* FROM "projects" WHERE "projects"."namespace_id" IN (WITH RECURSIVE "base_and_descendants" AS ((SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 9970)
UNION
(SELECT "namespaces".* FROM "namespaces", "base_and_descendants" WHERE "namespaces"."type" = 'Group' AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "namespaces"."id" FROM "base_and_descendants" AS "namespaces")) projects JOIN LATERAL (SELECT "events"."created_at", "events"."target_id" FROM "events" WHERE (projects.id = project_id) AND "events"."action" = 7 ORDER BY "events"."id" DESC LIMIT 1) events ON true ORDER BY events.created_at DESC
New query (with lateral, cte and ordering MergeRequests on array_position) - this includes fetching MergeRequests too, so we do not have to fire another query like we had been doing till now:
explain WITH "ordered_events_cte" AS (SELECT events.target_id as target_id FROM "projects" JOIN LATERAL (SELECT "events"."created_at", "events"."target_id" FROM "events" WHERE (projects.id = project_id) AND "events"."action" = 7 ORDER BY "events"."id" DESC LIMIT 1) events ON true WHERE "projects"."namespace_id" IN (WITH RECURSIVE "base_and_descendants" AS ((SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 9970)
UNION
(SELECT "namespaces".* FROM "namespaces", "base_and_descendants" WHERE "namespaces"."type" = 'Group' AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "namespaces"."id" FROM "base_and_descendants" AS "namespaces") ORDER BY events.created_at DESC) SELECT "merge_requests".* FROM "merge_requests" INNER JOIN "ordered_events_cte" ON "merge_requests"."id" = "ordered_events_cte"."target_id" ORDER BY array_position(ARRAY(SELECT target_id FROM ordered_events_cte), merge_requests.id)
Screenshots
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team
Edited by Manoj M J