Skip to content

Avoid N + 1 queries when fetching a list of groups via GraphQL

What does this MR do and why?

Eliminates another N + 1 query when fetching a list of groups via the GraphQL API. Specifically the query to check if a group's feature is enabled.

Queries generated before this change
SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (166, 164, 165, 167, 168, 170) 
SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (166, 164, 165, 167, 168, 170) 
SELECT MAX("members"."access_level") AS maximum_access_level, "hierarchy"."id" AS hierarchy_id FROM "members" LEFT OUTER JOIN "users" ON "members"."user_id" = "users"."id" INNER JOIN (SELECT id, unnest(traversal_ids) as traversal_id FROM "namespaces" WHERE "namespaces"."id" IN (166, 164, 165, 167, 168, 170)) as hierarchy ON members.source_id = hierarchy.traversal_id WHERE "members"."type" = 'GroupMember' AND "members"."source_type" = 'Namespace' AND "users"."state" = 'active' AND "members"."requested_at" IS NULL AND "members"."invite_token" IS NULL AND (members.access_level > 5) AND "members"."user_id" = 14 GROUP BY "hierarchy"."id" 
SELECT namespaces.*, root_query.id as source_id FROM "namespaces" INNER JOIN (SELECT id, traversal_ids[1] as root_id FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (166, 164, 165, 167, 168, 170)) as root_query ON root_query.root_id = namespaces.id 
SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (162, 165, 166, 167, 169) 
SELECT "saml_providers".* FROM "saml_providers" WHERE "saml_providers"."group_id" IN (162, 165, 166, 167, 169) 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" = 166
SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (162, 164) 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" IN (162, 164) 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" = 165 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" = 167 
SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (162, 164, 168) 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" IN (162, 164, 168)
SELECT "namespaces"."id" FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (169, 170) 
SELECT DISTINCT "plans".* FROM "plans" INNER JOIN "gitlab_subscriptions" ON "gitlab_subscriptions"."hosted_plan_id" = "plans"."id" WHERE "plans"."name" IN ('bronze', 'silver', 'premium', 'gold', 'ultimate', 'ultimate_trial', 'premium_trial') AND "gitlab_subscriptions"."namespace_id" IN (169, 170)
Queries generated after this change
SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (176, 174, 175, 177, 178, 180)
SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (176, 174, 175, 177, 178, 180)
SELECT MAX("members"."access_level") AS maximum_access_level, "hierarchy"."id" AS hierarchy_id FROM "members" LEFT OUTER JOIN "users" ON "members"."user_id" = "users"."id" INNER JOIN (SELECT id, unnest(traversal_ids) as traversal_id FROM "namespaces" WHERE "namespaces"."id" IN (176, 174, 175, 177, 178, 180)) as hierarchy ON members.source_id = hierarchy.traversal_id WHERE "members"."type" = 'GroupMember' AND "members"."source_type" = 'Namespace' AND "users"."state" = 'active' AND "members"."requested_at" IS NULL AND "members"."invite_token" IS NULL AND (members.access_level > 5) AND "members"."user_id" = 15 GROUP BY "hierarchy"."id"
SELECT namespaces.*, root_query.id as source_id FROM "namespaces" INNER JOIN (SELECT id, traversal_ids[1] as root_id FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (176, 174, 175, 177, 178, 180)) as root_query ON root_query.root_id = namespaces.id
SELECT "ip_restrictions".* FROM "ip_restrictions" WHERE "ip_restrictions"."group_id" IN (172, 175, 176, 177, 179)
SELECT "saml_providers".* FROM "saml_providers" WHERE "saml_providers"."group_id" IN (172, 175, 176, 177, 179)
SELECT "namespaces"."id", "namespaces"."parent_id", "gitlab_subscriptions"."hosted_plan_id" FROM (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"."description_html", "namespaces"."lfs_enabled", "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" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (SELECT unnest(traversal_ids) FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" IN (176, 174, 175, 177, 178, 180))) namespaces LEFT OUTER JOIN gitlab_subscriptions ON gitlab_subscriptions.namespace_id=namespaces.id WHERE "namespaces"."type" = 'Group'

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #343815 (closed)

Edited by Mario Celi

Merge request reports

Loading