diff --git a/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/down.sql b/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/down.sql new file mode 100644 index 0000000000..8efd172ad6 --- /dev/null +++ b/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/down.sql @@ -0,0 +1,23 @@ +create or replace function merlin.get_dependent_activities(_activity_id int, _plan_id int) + returns table(activity_id int, total_offset interval) + stable + language plpgsql as $$ +begin + return query + with recursive d_activities(activity_id, anchor_id, anchored_to_start, start_offset, total_offset) as ( + select ad.id, ad.anchor_id, ad.anchored_to_start, ad.start_offset, ad.start_offset + from merlin.activity_directive ad + where (ad.anchor_id, ad.plan_id) = (_activity_id, _plan_id) + union + select ad.id, ad.anchor_id, ad.anchored_to_start, ad.start_offset, da.total_offset + ad.start_offset + from merlin.activity_directive ad, d_activities da + where (ad.anchor_id, ad.plan_id) = (da.activity_id, _plan_id) + and ad.anchored_to_start + ) select da.activity_id, da.total_offset + from d_activities da; +end; +$$; + +drop index if exists merlin.activity_directive_anchor_id_index; + +call migrations.mark_migration_rolled_back(35); diff --git a/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/up.sql b/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/up.sql new file mode 100644 index 0000000000..d28a3dcd41 --- /dev/null +++ b/deployment/hasura/migrations/Aerie/35_activity_directive_anchor_index/up.sql @@ -0,0 +1,24 @@ +-- Used by merlin.get_dependent_activities (called per row from validate_anchors_insert_trigger). +create index activity_directive_anchor_id_index + on merlin.activity_directive (anchor_id, plan_id); + +-- `language sql` (not plpgsql) so the planner can inline this into the calling +-- query and pick the index above. The plpgsql wrapper was opaque to the planner. +create or replace function merlin.get_dependent_activities(_activity_id int, _plan_id int) + returns table(activity_id int, total_offset interval) + stable + language sql as $$ + with recursive d_activities(activity_id, anchor_id, anchored_to_start, start_offset, total_offset) as ( + select ad.id, ad.anchor_id, ad.anchored_to_start, ad.start_offset, ad.start_offset + from merlin.activity_directive ad + where (ad.anchor_id, ad.plan_id) = (_activity_id, _plan_id) + union + select ad.id, ad.anchor_id, ad.anchored_to_start, ad.start_offset, da.total_offset + ad.start_offset + from merlin.activity_directive ad, d_activities da + where (ad.anchor_id, ad.plan_id) = (da.activity_id, _plan_id) + and ad.anchored_to_start + ) select da.activity_id, da.total_offset + from d_activities da; +$$; + +call migrations.mark_migration_applied(35); diff --git a/deployment/postgres-init-db/sql/tables/merlin/activity_directive/activity_directive.sql b/deployment/postgres-init-db/sql/tables/merlin/activity_directive/activity_directive.sql index 5ddafbb641..cb31084efd 100644 --- a/deployment/postgres-init-db/sql/tables/merlin/activity_directive/activity_directive.sql +++ b/deployment/postgres-init-db/sql/tables/merlin/activity_directive/activity_directive.sql @@ -54,6 +54,10 @@ create table merlin.activity_directive ( create index activity_directive_plan_id_index on merlin.activity_directive (plan_id); +-- Used by merlin.get_dependent_activities (called per row from validate_anchors_insert_trigger). +create index activity_directive_anchor_id_index + on merlin.activity_directive (anchor_id, plan_id); + comment on table merlin.activity_directive is e'' 'A single activity_directive within a plan.'; diff --git a/deployment/postgres-init-db/sql/tables/merlin/activity_directive/anchor_validation_status.sql b/deployment/postgres-init-db/sql/tables/merlin/activity_directive/anchor_validation_status.sql index 5484b89736..55e441c840 100644 --- a/deployment/postgres-init-db/sql/tables/merlin/activity_directive/anchor_validation_status.sql +++ b/deployment/postgres-init-db/sql/tables/merlin/activity_directive/anchor_validation_status.sql @@ -24,12 +24,13 @@ comment on column merlin.anchor_validation_status.plan_id is e'' comment on column merlin.anchor_validation_status.reason_invalid is e'' 'If null, the anchor is valid. If not null, this contains a reason why the anchor is invalid.'; +-- `language sql` (not plpgsql) so the planner can inline this into the calling +-- query and pick the (anchor_id, plan_id) index. The plpgsql wrapper was opaque +-- to the planner and chose a worse plan. create function merlin.get_dependent_activities(_activity_id int, _plan_id int) returns table(activity_id int, total_offset interval) stable - language plpgsql as $$ -begin - return query + language sql as $$ with recursive d_activities(activity_id, anchor_id, anchored_to_start, start_offset, total_offset) as ( select ad.id, ad.anchor_id, ad.anchored_to_start, ad.start_offset, ad.start_offset from merlin.activity_directive ad @@ -41,7 +42,6 @@ begin and ad.anchored_to_start -- stop at next end-time anchor ) select da.activity_id, da.total_offset from d_activities da; -end; $$; comment on function merlin.get_dependent_activities(_activity_id int, _plan_id int) is e''