Skip to content

Use linear versions of descendants in GroupDescendantsFinder

What does this MR do?

In this MR, we're switching the behavior of two methods in GroupDescendantsFinder to use the linear version. The new behavior is behind the linear_group_descendants_finder feature flag.

How to setup and validate locally (strongly suggested)

  1. Enable the new method behavior feature flag
    Feature.enable(:linear_group_descendants_finder)
  2. In rails console enable the traversal id feature flag
    Feature.enable(:use_traversal_ids)

SQL Queries

The namespaces used in these queries have eleven children and the user id used is the one for the gitlab-qa user.

GroupDescendantsFinder#projects_matching_filter

The former sql was:

SELECT *
FROM "projects"
WHERE (EXISTS
         (SELECT 1
          FROM "project_authorizations"
          WHERE "project_authorizations"."user_id" = 1
            AND (project_authorizations.project_id = projects.id))
       OR projects.visibility_level IN (0,
                                        10,
                                        20))
  AND "projects"."id" IN
    (SELECT "projects"."id"
     FROM "projects"
     WHERE "projects"."namespace_id" IN
         (WITH RECURSIVE "base_and_descendants" AS (
                                                      (SELECT *
                                                       FROM "namespaces"
                                                       WHERE "namespaces"."type" = 'Group'
                                                         AND "namespaces"."id" = 9970)
                                                    UNION
                                                      (SELECT *
                                                       FROM "namespaces",
                                                            "base_and_descendants"
                                                       WHERE "namespaces"."type" = 'Group'
                                                         AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT "id"
          FROM "base_and_descendants" AS "namespaces"))
  AND (("projects"."path" ILIKE '%gitlab%'
        OR "projects"."name" ILIKE '%gitlab%')
       OR "projects"."description" ILIKE '%gitlab%')
  AND "projects"."archived" = FALSE
ORDER BY "projects"."id" DESC

This is the plan for the query and the time summary is:

Time: 54.135 ms
  - planning: 13.216 ms
  - execution: 40.919 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 12764 (~99.70 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

The new sql is:

SELECT *
FROM "projects"
WHERE (EXISTS
         (SELECT 1
          FROM "project_authorizations"
          WHERE "project_authorizations"."user_id" = 1
            AND (project_authorizations.project_id = projects.id))
       OR projects.visibility_level IN (0,
                                        10,
                                        20))
  AND "projects"."id" IN
    (SELECT "projects"."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 @> ('{9970}'))))
  AND (("projects"."path" ILIKE '%gitlab%'
        OR "projects"."name" ILIKE '%gitlab%')
       OR "projects"."description" ILIKE '%gitlab%')
  AND "projects"."archived" = FALSE
ORDER BY "projects"."id" DESC

This is the query plan and the time summary is:

Time: 42.190 ms
  - planning: 7.861 ms
  - execution: 34.329 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 11708 (~91.50 MiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

GroupDescendantsFinder#all_visible_descendant_groups

The former sql was:

WITH RECURSIVE base_and_descendants AS (
                                          (SELECT namespaces.*
                                           FROM namespaces
                                           WHERE namespaces.type = 'Group'
                                             AND namespaces.id = 2089817)
                                        UNION
                                          (SELECT namespaces.*
                                           FROM namespaces,
                                                base_and_descendants
                                           WHERE namespaces.type = 'Group'
                                             AND namespaces.parent_id = base_and_descendants.id))
SELECT namespaces.*
FROM base_and_descendants AS namespaces
WHERE namespaces.id NOT IN
    (SELECT namespaces.id
     FROM namespaces
     WHERE namespaces.type = 'Group'
       AND namespaces.id = 2089817)
  AND (namespaces.visibility_level IN (10,
                                       20)
       OR EXISTS
         (SELECT 1
          FROM
            (WITH RECURSIVE base_and_ancestors AS (
                                                     (SELECT namespaces.*
                                                      FROM (
                                                              (WITH direct_groups AS MATERIALIZED
                                                                 (SELECT namespaces.*
                                                                  FROM (
                                                                          (SELECT namespaces.*
                                                                           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 = 1614863
                                                                             AND members.requested_at IS NULL
                                                                             AND (access_level >= 10))
                                                                        UNION
                                                                          (SELECT namespaces.*
                                                                           FROM projects
                                                                           INNER JOIN project_authorizations ON projects.id = project_authorizations.project_id
                                                                           INNER JOIN namespaces ON namespaces.id = projects.namespace_id
                                                                           WHERE project_authorizations.user_id = 1614863)) namespaces
                                                                  WHERE namespaces.type = 'Group') SELECT namespaces.*
                                                               FROM (
                                                                       (SELECT namespaces.*
                                                                        FROM direct_groups namespaces
                                                                        WHERE namespaces.type = 'Group')
                                                                     UNION
                                                                       (SELECT namespaces.*
                                                                        FROM namespaces
                                                                        INNER JOIN group_group_links ON group_group_links.shared_group_id = namespaces.id
                                                                        WHERE namespaces.type = 'Group'
                                                                          AND group_group_links.shared_with_group_id IN
                                                                            (SELECT namespaces.id
                                                                             FROM direct_groups namespaces
                                                                             WHERE namespaces.type = 'Group'))) namespaces
                                                               WHERE namespaces.type = 'Group')) namespaces
                                                      WHERE namespaces.type = 'Group')
                                                   UNION
                                                     (SELECT namespaces.*
                                                      FROM namespaces,
                                                           base_and_ancestors
                                                      WHERE namespaces.type = 'Group'
                                                        AND namespaces.id = base_and_ancestors.parent_id)),
                            base_and_descendants AS (
                                                       (SELECT namespaces.*
                                                        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 = 1614863
                                                          AND members.requested_at IS NULL
                                                          AND (access_level >= 10))
                                                     UNION
                                                       (SELECT namespaces.*
                                                        FROM namespaces,
                                                             base_and_descendants
                                                        WHERE namespaces.type = 'Group'
                                                          AND namespaces.parent_id = base_and_descendants.id)) SELECT namespaces.*
             FROM (
                     (SELECT namespaces.*
                      FROM base_and_ancestors AS namespaces
                      WHERE namespaces.type = 'Group')
                   UNION
                     (SELECT namespaces.*
                      FROM base_and_descendants AS namespaces
                      WHERE namespaces.type = 'Group')) namespaces
             WHERE namespaces.type = 'Group'
             ORDER BY namespaces.id DESC) authorized
          WHERE authorized.id = namespaces.id))

This is the query plan and the time summary is:

Time: 22.154 ms
  - planning: 17.915 ms
  - execution: 4.239 ms
    - I/O read: 0.000 ms
    - I/O write: 0.000 ms

Shared buffers:
  - hits: 3 (~24.00 KiB) from the buffer pool
  - reads: 0 from the OS file cache, including disk I/O
  - dirtied: 0
  - writes: 0

The new sql is:

SELECT "namespaces".*
FROM "namespaces"
WHERE "namespaces"."type" = 'Group'
  AND (traversal_ids @> ('{9970}'))
  AND "namespaces"."id" != 9970
  AND ("namespaces"."visibility_level" IN (0,
                                           10,
                                           20)
       OR EXISTS
         (SELECT 1
          FROM
            (WITH RECURSIVE "base_and_ancestors" AS (
                                                       (SELECT *
                                                        FROM (
                                                                (WITH "direct_groups" AS MATERIALIZED
                                                                   (SELECT *
                                                                    FROM (
                                                                            (SELECT "namespaces".*
                                                                             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" = 1
                                                                               AND "members"."requested_at" IS NULL
                                                                               AND (access_level >= 10))
                                                                          UNION
                                                                            (SELECT "namespaces".*
                                                                             FROM "projects"
                                                                             INNER JOIN "project_authorizations" ON "projects"."id" = "project_authorizations"."project_id"
                                                                             INNER JOIN "namespaces" ON "namespaces"."id" = "projects"."namespace_id"
                                                                             WHERE "project_authorizations"."user_id" = 1)) namespaces
                                                                    WHERE "namespaces"."type" = 'Group') SELECT *
                                                                 FROM (
                                                                         (SELECT "namespaces".*
                                                                          FROM "direct_groups" "namespaces"
                                                                          WHERE "namespaces"."type" = 'Group')
                                                                       UNION
                                                                         (SELECT "namespaces".*
                                                                          FROM "namespaces"
                                                                          INNER JOIN "group_group_links" ON "group_group_links"."shared_group_id" = "namespaces"."id"
                                                                          WHERE "namespaces"."type" = 'Group'
                                                                            AND "group_group_links"."shared_with_group_id" IN
                                                                              (SELECT "namespaces"."id"
                                                                               FROM "direct_groups" "namespaces"
                                                                               WHERE "namespaces"."type" = 'Group'))) namespaces
                                                                 WHERE "namespaces"."type" = 'Group')
                                                              UNION
                                                                (SELECT *
                                                                 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" = 1
                                                                   AND "members"."access_level" = 5)) namespaces
                                                        WHERE "namespaces"."type" = 'Group')
                                                     UNION
                                                       (SELECT "namespaces".*
                                                        FROM "namespaces",
                                                             "base_and_ancestors"
                                                        WHERE "namespaces"."type" = 'Group'
                                                          AND "namespaces"."id" = "base_and_ancestors"."parent_id")),
                            "base_and_descendants" AS (
                                                         (SELECT "namespaces".*
                                                          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" = 1
                                                            AND "members"."requested_at" IS NULL
                                                            AND (access_level >= 10))
                                                       UNION
                                                         (SELECT "namespaces".*
                                                          FROM "namespaces",
                                                               "base_and_descendants"
                                                          WHERE "namespaces"."type" = 'Group'
                                                            AND "namespaces"."parent_id" = "base_and_descendants"."id")) SELECT *
             FROM (
                     (SELECT "namespaces".*
                      FROM "base_and_ancestors" AS "namespaces"
                      WHERE "namespaces"."type" = 'Group')
                   UNION
                     (SELECT "namespaces".*
                      FROM "base_and_descendants" AS "namespaces"
                      WHERE "namespaces"."type" = 'Group')) namespaces
             WHERE "namespaces"."type" = 'Group'
             ORDER BY "namespaces"."id" DESC) authorized
          WHERE authorized."id" = "namespaces"."id"))

This is the query plan and the time summary:

Planning Time: 15.880 ms
Execution Time: 5.202 ms

Does this MR meet the acceptance criteria?

Conformity

Related to #332298 (closed)

Edited by Francisco Javier López

Merge request reports

Loading