Draft: Optimize query to get all project related to a security policy configuration
What does this MR do and why?
Use the InOperatorOptimization helper to optimize querying all projects for a OrchestrationPolicyConfiguration.
💾 Database
Old query
Query
SELECT
projects.id,
projects.name,
projects.path,
projects.description,
projects.created_at,
projects.updated_at,
projects.creator_id,
projects.namespace_id,
projects.last_activity_at,
projects.import_url,
projects.visibility_level,
projects.archived,
projects.avatar,
projects.merge_requests_template,
projects.star_count,
projects.merge_requests_rebase_enabled,
projects.import_type,
projects.import_source,
projects.approvals_before_merge,
projects.reset_approvals_on_push,
projects.merge_requests_ff_only_enabled,
projects.issues_template,
projects.mirror,
projects.mirror_last_update_at,
projects.mirror_last_successful_update_at,
projects.mirror_user_id,
projects.shared_runners_enabled,
projects.runners_token,
projects.build_allow_git_fetch,
projects.build_timeout,
projects.mirror_trigger_builds,
projects.pending_delete,
projects.public_builds,
projects.last_repository_check_failed,
projects.last_repository_check_at,
projects.only_allow_merge_if_pipeline_succeeds,
projects.has_external_issue_tracker,
projects.repository_storage,
projects.repository_read_only,
projects.request_access_enabled,
projects.has_external_wiki,
projects.ci_config_path,
projects.lfs_enabled,
projects.description_html,
projects.only_allow_merge_if_all_discussions_are_resolved,
projects.repository_size_limit,
projects.printing_merge_request_link_enabled,
projects.auto_cancel_pending_pipelines,
projects.service_desk_enabled,
projects.cached_markdown_version,
projects.delete_error,
projects.last_repository_updated_at,
projects.disable_overriding_approvers_per_merge_request,
projects.storage_version,
projects.resolve_outdated_diff_discussions,
projects.remote_mirror_available_overridden,
projects.only_mirror_protected_branches,
projects.pull_mirror_available_overridden,
projects.jobs_cache_index,
projects.external_authorization_classification_label,
projects.mirror_overwrites_diverged_branches,
projects.pages_https_only,
projects.external_webhook_token,
projects.packages_enabled,
projects.merge_requests_author_approval,
projects.pool_repository_id,
projects.runners_token_encrypted,
projects.bfg_object_map,
projects.detected_repository_languages,
projects.merge_requests_disable_committers_approval,
projects.require_password_to_approve,
projects.max_pages_size,
projects.max_artifacts_size,
projects.pull_mirror_branch_prefix,
projects.remove_source_branch_after_merge,
projects.marked_for_deletion_at,
projects.marked_for_deletion_by_user_id,
projects.autoclose_referenced_issues,
projects.suggestion_commit_message,
projects.project_namespace_id,
projects.hidden,
projects.organization_id
FROM
projects
WHERE
projects.namespace_id IN (
SELECT
namespaces.traversal_ids[array_length(
namespaces.traversal_ids,
1
)] AS id
FROM
namespaces
WHERE
namespaces.type = 'Group' AND
traversal_ids @> '{64772824}'
);
Time: 11.911 ms
- planning: 9.157 ms
- execution: 2.754 ms
- I/O read: 0.000 ms
- I/O write: 0.000 ms
Shared buffers:
- hits: 235 (~1.80 MiB) from the buffer pool
- reads: 0 from the OS file cache, including disk I/O
- dirtied: 0
- writes: 0
New query
Query
SELECT
*
FROM (WITH RECURSIVE "array_cte" AS MATERIALIZED (
SELECT
namespaces.traversal_ids[array_length(
namespaces.traversal_ids, 1
)] AS id
FROM
"namespaces"
WHERE
"namespaces"."type" = 'Group'
AND (
traversal_ids @> (
'{64772824}'
)
)
), "recursive_keyset_cte" AS ((
SELECT
NULL::integer AS id, array_cte_id_array, projects_id_array, 0::bigint AS count
FROM (
SELECT
ARRAY_AGG("array_cte".id) AS array_cte_id_array,
ARRAY_AGG("projects"."id") AS projects_id_array
FROM (
SELECT
"array_cte".id
FROM
array_cte) array_cte
LEFT JOIN LATERAL (
SELECT
"projects"."id" AS id
FROM
"projects"
WHERE
"projects"."namespace_id" = "array_cte".id
AND "projects"."marked_for_deletion_at" IS NULL
AND "projects"."pending_delete" = FALSE
ORDER BY
"projects"."id" ASC
LIMIT 1) projects ON TRUE
WHERE
"projects"."id" IS NOT NULL) array_scope_lateral_query
LIMIT 1)
UNION ALL (
SELECT
recursive_keyset_cte.projects_id_array[position],
array_cte_id_array,
recursive_keyset_cte.projects_id_array[:position_query.position - 1] || next_cursor_values.id || recursive_keyset_cte.projects_id_array[position_query.position + 1:],
recursive_keyset_cte.count + 1
FROM
recursive_keyset_cte,
LATERAL (
SELECT
id,
position
FROM
UNNEST(projects_id_array
)
WITH ORDINALITY AS u (id,
position)
WHERE
id IS NOT NULL
ORDER BY
1 ASC
LIMIT 1) AS position_query,
LATERAL (
SELECT
"record"."id"
FROM (
VALUES (NULL)) AS nulls
LEFT JOIN (
SELECT
"projects"."id" AS id
FROM
"projects"
WHERE
"projects"."namespace_id" = recursive_keyset_cte.array_cte_id_array[position]
AND "projects"."marked_for_deletion_at" IS NULL
AND "projects"."pending_delete" = FALSE
AND ("projects"."id" > recursive_keyset_cte.projects_id_array[position])
ORDER BY
"projects"."id" ASC
LIMIT 1) record ON TRUE
LIMIT 1) AS next_cursor_values))
SELECT
id
FROM
"recursive_keyset_cte" AS "projects"
WHERE (count <> 0)
) projects
Time: 13.860 ms
- planning: 9.565 ms
- execution: 4.295 ms
- I/O read: 0.000 ms
- I/O write: 0.000 ms
Shared buffers:
- hits: 551 (~4.30 MiB) from the buffer pool
- reads: 0 from the OS file cache, including disk I/O
- dirtied: 0
- writes: 0
Screenshots or screen recordings
Screenshots are required for UI changes, and strongly recommended for all other merge requests.
Before | After |
---|---|
How to set up and validate locally
Numbered steps to set up and validate the change are strongly suggested.
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #407269 (closed)
Edited by Andy Schoenen