Group project template tab can't be opened on Sass

Summary

https://gitlab.com/projects/new#create_from_template page is slow because it executes the following SQL query:

Query
SELECT COUNT(*)
FROM “projects”
WHERE “projects”.“namespace_id” IN
    (WITH RECURSIVE “base_and_descendants” AS (
                                                 (SELECT “namespaces”.“id”, “namespaces”.“name”, “namespaces”.“PATH”, “namespaces”.“owner_id”, “namespaces”.“created_at”, “namespaces”.“updated_at”, “namespaces”.“TYPE”, “namespaces”.“description”, “namespaces”.“avatar”, “namespaces”.“membership_lock”, “namespaces”.“share_with_group_lock”, “namespaces”.“visibility_level”, “namespaces”.“request_access_enabled”, “namespaces”.“ldap_sync_status”, “namespaces”.“ldap_sync_error”, “namespaces”.“ldap_sync_last_update_at”, “namespaces”.“ldap_sync_last_successful_update_at”, “namespaces”.“ldap_sync_last_sync_at”, “namespaces”.“lfs_enabled”, “namespaces”.“description_html”, “namespaces”.“parent_id”, “namespaces”.“shared_runners_minutes_limit”, “namespaces”.“repository_size_limit”, “namespaces”.“require_two_factor_authentication”, “namespaces”.“two_factor_grace_period”, “namespaces”.“cached_markdown_version”, “namespaces”.“project_creation_level”, “namespaces”.“runners_token”, “namespaces”.“file_template_project_id”, “namespaces”.“saml_discovery_token”, “namespaces”.“runners_token_encrypted”, “namespaces”.“custom_project_templates_group_id”, “namespaces”.“auto_devops_enabled”, “namespaces”.“extra_shared_runners_minutes_limit”, “namespaces”.“last_ci_minutes_notification_at”, “namespaces”.“last_ci_minutes_usage_notification_level”, “namespaces”.“subgroup_creation_level”, “namespaces”.“emails_disabled”, “namespaces”.“max_pages_size”, “namespaces”.“max_artifacts_size”, “namespaces”.“mentions_disabled”, “namespaces”.“default_branch_protection”, “namespaces”.“unlock_membership_to_ldap”, “namespaces”.“max_personal_access_token_lifetime”, “namespaces”.“push_rule_id”, “namespaces”.“shared_runners_enabled”, “namespaces”.“allow_descendants_override_disabled_shared_runners”, “namespaces”.“traversal_ids”
                                                  FROM “namespaces”
                                                  INNER JOIN “members” ON “namespaces”.“id” = “members”.“source_id”
                                                  WHERE “members”.“TYPE” = ‘GroupMember’
                                                    AND “members”.“source_type” = ‘Namespace’
                                                    AND “namespaces”.“TYPE” = ‘GROUP’
                                                    AND “members”.“user_id” = 1161495
                                                    AND “members”.“requested_at” IS NULL
                                                    AND (access_level >= 10)
                                                    AND (members.access_level >= 30))
                                               UNION
                                                 (SELECT “namespaces”.“id”, “namespaces”.“name”, “namespaces”.“PATH”, “namespaces”.“owner_id”, “namespaces”.“created_at”, “namespaces”.“updated_at”, “namespaces”.“TYPE”, “namespaces”.“description”, “namespaces”.“avatar”, “namespaces”.“membership_lock”, “namespaces”.“share_with_group_lock”, “namespaces”.“visibility_level”, “namespaces”.“request_access_enabled”, “namespaces”.“ldap_sync_status”, “namespaces”.“ldap_sync_error”, “namespaces”.“ldap_sync_last_update_at”, “namespaces”.“ldap_sync_last_successful_update_at”, “namespaces”.“ldap_sync_last_sync_at”, “namespaces”.“lfs_enabled”, “namespaces”.“description_html”, “namespaces”.“parent_id”, “namespaces”.“shared_runners_minutes_limit”, “namespaces”.“repository_size_limit”, “namespaces”.“require_two_factor_authentication”, “namespaces”.“two_factor_grace_period”, “namespaces”.“cached_markdown_version”, “namespaces”.“project_creation_level”, “namespaces”.“runners_token”, “namespaces”.“file_template_project_id”, “namespaces”.“saml_discovery_token”, “namespaces”.“runners_token_encrypted”, “namespaces”.“custom_project_templates_group_id”, “namespaces”.“auto_devops_enabled”, “namespaces”.“extra_shared_runners_minutes_limit”, “namespaces”.“last_ci_minutes_notification_at”, “namespaces”.“last_ci_minutes_usage_notification_level”, “namespaces”.“subgroup_creation_level”, “namespaces”.“emails_disabled”, “namespaces”.“max_pages_size”, “namespaces”.“max_artifacts_size”, “namespaces”.“mentions_disabled”, “namespaces”.“default_branch_protection”, “namespaces”.“unlock_membership_to_ldap”, “namespaces”.“max_personal_access_token_lifetime”, “namespaces”.“push_rule_id”, “namespaces”.“shared_runners_enabled”, “namespaces”.“allow_descendants_override_disabled_shared_runners”, “namespaces”.“traversal_ids”
                                                  FROM “namespaces”, “base_and_descendants”
                                                  WHERE “namespaces”.“TYPE” = ‘GROUP’
                                                    AND “namespaces”.“parent_id” = “base_and_descendants”.“id”)) SELECT DISTINCT “namespaces”.“id”
     FROM “base_and_descendants” AS “namespaces”
     INNER JOIN “projects” ON “projects”.“namespace_id” = “namespaces”.“id”
     WHERE “namespaces”.“id” IN
         (WITH “descendants_base_cte” AS MATERIALIZED
            (WITH “base_ancestors_cte” AS MATERIALIZED
               (SELECT “namespaces”.“traversal_ids”
                FROM “namespaces”
                WHERE “namespaces”.“TYPE” = ‘GROUP’
                  AND “namespaces”.“custom_project_templates_group_id” IS NOT NULL) SELECT “id”, “traversal_ids”
             FROM “namespaces”
             INNER JOIN
               (SELECT DISTINCT unnest(“base_ancestors_cte”.“traversal_ids”)
                FROM base_ancestors_cte) AS ancestors(ancestor_id) ON namespaces.id = ancestors.ancestor_id
             WHERE “namespaces”.“TYPE” = ‘GROUP’
               AND (EXISTS
                      (SELECT 1
                       FROM “plans”
                       INNER JOIN “gitlab_subscriptions” ON “gitlab_subscriptions”.“hosted_plan_id” = “plans”.“id”
                       WHERE “plans”.“name” IN (‘silver’, ‘premium’, ‘premium_trial’, ‘gold’, ‘ultimate’, ‘ultimate_trial’, ‘opensource’)
                         AND (gitlab_subscriptions.namespace_id = namespaces.id)))), “superset” AS
            (SELECT d1.traversal_ids
             FROM descendants_base_cte d1
             WHERE NOT EXISTS
                 (SELECT 1
                  FROM descendants_base_cte d2
                  WHERE d2.id = ANY(d1.traversal_ids)
                    AND d2.id <> d1.id ) ) SELECT DISTINCT “custom_project_templates_group_id”
          FROM “superset”, “namespaces”
          WHERE “namespaces”.“TYPE” = ‘GROUP’
            AND next_traversal_ids_sibling(“superset”.“traversal_ids”) > “namespaces”.“traversal_ids”
            AND “superset”.“traversal_ids” <= “namespaces”.“traversal_ids”
            AND “namespaces”.“custom_project_templates_group_id” IS NOT NULL))
  AND “projects”.“marked_for_deletion_at” IS NULL
  AND “projects”.“pending_delete” = FALSE

Query plan: https://files.slack.com/files-pri/T02592416-F0491S26QCU/plan-text.txt

The Group 65 tab can't be opened because it executes multiple similar queries.

Steps to reproduce

Example Project

What is the current bug behavior?

  • Projects#new page is slower
  • Group project templates tab can't be opened

What is the expected correct behavior?

  • The slow query is faster or not executed
  • Group project templates tab can be opened

Relevant logs and/or screenshots

Screenshot_2022-11-01_at_15.11.17

Possible fixes