Below is my postgresql materialize view code
-- public.reporting_user_activity_contents source
CREATE MATERIALIZED VIEW public.reporting_user_activity_contents
TABLESPACE pg_default
AS WITH sub_q AS (
SELECT u.id AS user_id,
t.id AS tenant_id,
t.global_tenant_id,
m.id AS content_id,
m.title AS content_title,
um.id AS user_mission_id,
mk.id AS content_kind_id,
mk.kind AS content_kind,
gp.path_id,
gp.group_id AS assigned_through_group_id,
COALESCE(ugpr.hidden, false) AS hidden,
CASE
WHEN uv.created_at IS NOT NULL THEN uv.created_at
WHEN uv.created_at IS NULL THEN ugpr.viewed_at
ELSE NULL::timestamp without time zone
END AS first_viewed_at,
CASE
WHEN um.completed_at IS NOT NULL THEN um.completed_at
WHEN um.completed_at IS NULL THEN ugpr.completed_at
ELSE NULL::timestamp without time zone
END AS first_completed_at,
CASE
WHEN ugpr.discussed_at IS NOT NULL THEN ugpr.discussed_at
ELSE NULL::timestamp without time zone
END AS first_discussed_at,
CASE
WHEN gpr.discussable THEN gpr.discussable
ELSE false
END AS discussible,
( SELECT to_jsonb(array_to_json(array_agg(row_to_json(t_1.*)))) AS to_jsonb
FROM ( SELECT tags.id,
tags.name,
tags.taggings_count
FROM tags
JOIN taggings ON tags.id = taggings.tag_id
WHERE taggings.taggable_id = m.id AND taggings.taggable_type::text = 'Mission'::text AND (taggings.context::text = ANY (ARRAY['tags'::character varying::text, 'skills'::character varying::text, 'skill_groups'::character varying::text, 'levels'::character varying::text]))) t_1) AS tags
FROM missions m
JOIN user_missions um ON um.mission_id = m.id AND um.assigned_through_type::text = 'Space'::text
LEFT JOIN user_views uv ON uv.viewable_id = m.id AND uv.user_id = um.user_id AND uv.viewable_type::text = 'Mission'::text
JOIN mission_kinds mk ON mk.id = m.mission_kind_id
JOIN users u ON u.id = um.user_id
JOIN tenants t ON u.tenant_id = t.id
LEFT JOIN group_path_resources gpr ON gpr.id = uv.assigned_through_id AND uv.assigned_through_type::text = 'GroupPathResource'::text AND gpr.resourceable_type::text = 'Mission'::text AND gpr.resourceable_id = um.mission_id
LEFT JOIN group_path_sections gps ON gps.id = gpr.group_path_section_id
LEFT JOIN group_paths gp ON gp.id = gps.group_path_id
LEFT JOIN user_group_path_resources ugpr ON ugpr.group_path_resource_id = gpr.id AND ugpr.resourceable_id = um.id AND ugpr.resourceable_type::text = 'UserMission'::text
)
SELECT sub_q.user_id,
sub_q.tenant_id,
sub_q.global_tenant_id,
sub_q.content_id,
sub_q.content_title,
sub_q.user_mission_id,
sub_q.content_kind_id,
sub_q.content_kind,
sub_q.path_id,
sub_q.assigned_through_group_id,
sub_q.discussible,
sub_q.tags,
min(sub_q.first_viewed_at) AS first_viewed_at,
min(sub_q.first_completed_at) AS first_completed_at,
min(sub_q.first_discussed_at) AS first_discussed_at,
bool_and(sub_q.hidden) AS hidden
FROM sub_q
WHERE sub_q.tenant_id IS NOT NULL
GROUP BY sub_q.user_id, sub_q.tenant_id, sub_q.global_tenant_id, sub_q.content_id, sub_q.content_title, sub_q.user_mission_id, sub_q.content_kind_id, sub_q.content_kind, sub_q.path_id, sub_q.assigned_through_group_id, sub_q.discussible, sub_q.tags
WITH DATA;
— View indexes:
CREATE INDEX idx_u_t_gt_c_atg ON public.reporting_user_activity_contents USING btree (content_id, user_mission_id, user_id, tenant_id, global_tenant_id, assigned_through_group_id, path_id);
CREATE INDEX ruac_atg_p ON public.reporting_user_activity_contents USING btree (assigned_through_group_id, path_id);
CREATE INDEX ruac_t_gt ON public.reporting_user_activity_contents USING btree (tenant_id, global_tenant_id);
CREATE INDEX ruac_u_atg ON public.reporting_user_activity_contents USING btree (user_id, assigned_through_group_id);
To reduce the execution time , I changed the join structure and removed the filter column casting & also removed the where clause from outer query and added in cte ,
what are the changes required in this code to reduce execution time upto 50 seconds
explain analyze
WITH sub_q AS (
SELECT u.id AS user_id,
t.id AS tenant_id,
t.global_tenant_id,
m.id AS content_id,
m.title AS content_title,
um.id AS user_mission_id,
mk.id AS content_kind_id,
mk.kind AS content_kind,
gp.path_id,
gp.group_id AS assigned_through_group_id,
COALESCE(ugpr.hidden, false) AS hidden,
/* CASE
WHEN uv.created_at IS NOT NULL THEN uv.created_at
WHEN uv.created_at IS NULL THEN ugpr.viewed_at
ELSE NULL::timestamp without time zone
END AS first_viewed_at,
*/
COALESCE(uv.created_at, ugpr.viewed_at) AS first_viewed_at,
/*
CASE
WHEN um.completed_at IS NOT NULL THEN um.completed_at
WHEN um.completed_at IS NULL THEN ugpr.completed_at
ELSE NULL::timestamp without time zone
END AS first_completed_at,
*/
COALESCE(um.completed_at, ugpr.completed_at) AS first_completed_at,
/*CASE
WHEN ugpr.discussed_at IS NOT NULL THEN ugpr.discussed_at
ELSE NULL::timestamp without time zone
END AS first_discussed_at,
*/
ugpr.discussed_at AS first_discussed_at,
/*CASE
WHEN gpr.discussable THEN gpr.discussable
ELSE false
END AS discussible, */
COALESCE(gpr.discussable, false) AS discussible,
/*( SELECT to_jsonb(array_to_json(array_agg(row_to_json(t_1.*)))) AS to_jsonb
FROM
( SELECT tags.id,
tags.name,
tags.taggings_count
FROM tags
JOIN taggings ON tags.id = taggings.tag_id
WHERE taggings.taggable_id = m.id
AND taggings.taggable_type::text = 'Mission'::text
AND (taggings.context::text = ANY (ARRAY['tags'::character varying::text, 'skills'::character varying::text, 'skill_groups'::character varying::text, 'levels'::character varying::text]))
) t_1
) AS tags*/
(
SELECT jsonb_agg(jsonb_build_object('id', tags.id, 'name', tags.name, 'taggings_count', tags.taggings_count))
FROM taggings
JOIN tags ON tags.id = taggings.tag_id
WHERE taggings.taggable_id = m.id
AND taggings.taggable_type = 'Mission'
AND taggings.context = ANY (ARRAY['tags', 'skills', 'skill_groups', 'levels'])
) AS tags
/* FROM missions m
JOIN mission_kinds mk ON m.mission_kind_id = mk.id
JOIN user_missions um ON um.mission_id = m.id AND um.assigned_through_type = 'Space'
JOIN users u ON um.user_id = u.id
JOIN tenants t ON u.tenant_id = t.id
LEFT JOIN user_views uv ON uv.viewable_id = m.id AND uv.user_id = um.user_id AND uv.viewable_type = 'Mission'
LEFT JOIN group_path_resources gpr ON gpr.id = uv.assigned_through_id AND uv.assigned_through_type = 'GroupPathResource' AND gpr.resourceable_type = 'Mission' AND gpr.resourceable_id = um.mission_id
LEFT JOIN group_path_sections gps ON gps.id = gpr.group_path_section_id
LEFT JOIN group_paths gp ON gp.id = gps.group_path_id
LEFT JOIN user_group_path_resources ugpr ON ugpr.group_path_resource_id = gpr.id AND ugpr.resourceable_id = um.id AND ugpr.resourceable_type = 'UserMission'
WHERE t.id IS NOT NULL*/
/*
from mission_kinds mk
join missions m ON mk.id = m.mission_kind_id
JOIN user_missions um ON um.mission_id = m.id AND um.assigned_through_type = 'Space'
JOIN users u ON u.id = um.user_id
JOIN tenants t ON u.tenant_id = t.id
LEFT JOIN user_views uv ON uv.viewable_id = m.id AND uv.user_id = um.user_id AND uv.viewable_type = 'Mission'
LEFT JOIN group_path_resources gpr ON gpr.id = uv.assigned_through_id AND uv.assigned_through_type= 'GroupPathResource' AND gpr.resourceable_type = 'Mission' AND gpr.resourceable_id = um.mission_id
LEFT JOIN group_path_sections gps ON gps.id = gpr.group_path_section_id
LEFT JOIN group_paths gp ON gp.id = gps.group_path_id
LEFT JOIN user_group_path_resources ugpr ON ugpr.group_path_resource_id = gpr.id AND ugpr.resourceable_id = um.id AND ugpr.resourceable_type = 'UserMission'
WHERE t.id IS NOT null
*/
FROM tenants t
JOIN users u ON u.tenant_id = t.id
JOIN user_missions um ON um.user_id = u.id AND um.assigned_through_type = 'Space'
JOIN missions m ON m.id = um.mission_id
LEFT JOIN user_views uv ON uv.user_id = u.id AND uv.viewable_id = m.id AND uv.viewable_type = 'Mission'
LEFT JOIN user_group_path_resources ugpr ON ugpr.resourceable_id = um.id AND ugpr.resourceable_type = 'UserMission'
LEFT JOIN group_path_resources gpr ON gpr.id = uv.assigned_through_id AND uv.assigned_through_type = 'GroupPathResource' AND gpr.resourceable_type = 'Mission' AND gpr.resourceable_id = um.mission_id
LEFT JOIN group_path_sections gps ON gps.id = gpr.group_path_section_id
LEFT JOIN group_paths gp ON gp.id = gps.group_path_id
LEFT JOIN mission_kinds mk ON mk.id = m.mission_kind_id
WHERE t.id IS NOT NULL
)
SELECT sub_q.user_id,
sub_q.tenant_id,
sub_q.global_tenant_id,
sub_q.content_id,
sub_q.content_title,
sub_q.user_mission_id,
sub_q.content_kind_id,
sub_q.content_kind,
sub_q.path_id,
sub_q.assigned_through_group_id,
sub_q.discussible,
sub_q.tags,
min(sub_q.first_viewed_at) AS first_viewed_at,
min(sub_q.first_completed_at) AS first_completed_at,
min(sub_q.first_discussed_at) AS first_discussed_at,
bool_and(sub_q.hidden) AS hidden
FROM sub_q
--WHERE sub_q.tenant_id IS NOT NULL
GROUP BY sub_q.user_id, sub_q.tenant_id, sub_q.global_tenant_id, sub_q.content_id, sub_q.content_title,
sub_q.user_mission_id, sub_q.content_kind_id, sub_q.content_kind, sub_q.path_id, sub_q.assigned_through_group_id, sub_q.discussible, sub_q.tags;
Explain plan is https://explain.depesz.com/s/C5vQ#stats