Fix/speedup for scheduling scope (#10341)

* LATERAL to reduce calculated descendants

The descendants are calculated to know when to stop calculating successors as they are (transitively) scheduled manually.

* linting
pull/10353/head
ulferts 3 years ago committed by GitHub
parent 06fee35e72
commit ec284d914e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 79
      app/models/work_packages/scopes/for_scheduling.rb

@ -119,51 +119,52 @@ module WorkPackages::Scopes
def paths_sql(work_packages)
values = work_packages.map { |wp| "(#{wp.id}, false)" }.join(', ')
<<~SQL
to_schedule (id, manually) AS (
SELECT * FROM (VALUES#{values}) AS t(id, manually)
<<~SQL.squish
to_schedule (id, manually) AS (
SELECT * FROM (VALUES#{values}) AS t(id, manually)
UNION
UNION
SELECT
CASE
WHEN relations.to_id = to_schedule.id
THEN relations.from_id
ELSE relations.to_id
END id,
(work_packages.schedule_manually OR COALESCE(descendants.schedule_manually, false)) manually
FROM
to_schedule
JOIN
relations
ON NOT to_schedule.manually
AND (#{relations_condition_sql})
AND
((relations.to_id = to_schedule.id)
OR (relations.from_id = to_schedule.id AND relations.follows = 0))
LEFT JOIN work_packages
ON (CASE
WHEN relations.to_id = to_schedule.id
THEN relations.from_id
ELSE relations.to_id
END) = work_packages.id
LEFT JOIN (
SELECT
relations.from_id,
bool_and(COALESCE(work_packages.schedule_manually, false)) schedule_manually
FROM relations relations
JOIN work_packages
ON
work_packages.id = relations.to_id
AND relations.follows = 0 AND #{relations_condition_sql(transitive: true)}
GROUP BY relations.from_id
) descendants ON work_packages.id = descendants.from_id
)
SELECT
CASE
WHEN relations.to_id = to_schedule.id
THEN relations.from_id
ELSE relations.to_id
END id,
(related_work_packages.schedule_manually OR COALESCE(descendants.schedule_manually, false)) manually
FROM
to_schedule
JOIN
relations
ON NOT to_schedule.manually
AND (#{relations_condition_sql})
AND
((relations.to_id = to_schedule.id)
OR (relations.from_id = to_schedule.id AND relations.follows = 0))
LEFT JOIN work_packages related_work_packages
ON (CASE
WHEN relations.to_id = to_schedule.id
THEN relations.from_id
ELSE relations.to_id
END) = related_work_packages.id
LEFT JOIN LATERAL (
SELECT
relations.from_id,
bool_and(COALESCE(work_packages.schedule_manually, false)) schedule_manually
FROM relations relations
JOIN work_packages
ON
work_packages.id = relations.to_id
AND related_work_packages.id = relations.from_id
AND relations.follows = 0 AND #{relations_condition_sql(transitive: true)}
GROUP BY relations.from_id
) descendants ON related_work_packages.id = descendants.from_id
)
SQL
end
def relations_condition_sql(transitive: false)
<<~SQL
<<~SQL.squish
"relations"."relates" = 0 AND "relations"."duplicates" = 0 AND "relations"."blocks" = 0 AND "relations"."includes" = 0 AND "relations"."requires" = 0
AND (relations.hierarchy + relations.relates + relations.duplicates + relations.follows + relations.blocks + relations.includes + relations.requires #{transitive ? '>' : ''}= 1)
SQL

Loading…
Cancel
Save