计数子查询太慢 SQL?

Count subqueries too slow SQL?

我必须制作一个 table,其中包含跨越不同 table 的许多不同计数.. 这些 table 可以合并,但我发现的一个问题是,当将它们合并在一起时,它会变成一个非常大的 table,需要一段时间才能加载。下面的查询需要大约 30 秒才能加载,有人知道我怎样才能让它更快吗?

SELECT  companies_company.id as company_id, companies_company.name as company_name, companies_company.office_location, companies_company.company_type,
(select count(*) from auth_user u where u.company_id = companies_company.id and (u.is_staff = 'false' or u.is_parent_company_admin ='false' or u.is_superuser = 'false') and u.email not ilike '%fake.com%' and u.email not ilike '%demo.com%') as company_user_count,
(select count(*) from auth_user u where u.company_id = companies_company.id and (u.is_staff = 'false' or u.is_parent_company_admin ='false' or u.is_superuser = 'false')  and u.email not ilike '%fake.com%' and u.email not ilike '%demo.com%'
   AND (u.last_activity >= date_trunc('day', now()) - interval '90 day' or u.last_login >= date_trunc('day', now()) - interval '90 day' )) as company_active_users_last_90_days,
   
(select count(*) from companies_learnergroup where companies_learnergroup.company_id = companies_company.id) as company_total_teams,
(select count(distinct auth_user.team_id) from auth_user where auth_user.company_id = companies_company.id and (auth_user.is_staff = 'false' or auth_user.is_parent_company_admin ='false' or auth_user.is_superuser = 'false') and auth_user.email not ilike '%fake.com%' and auth_user.email not ilike '%demo.com%' AND (auth_user.last_activity >= date_trunc('day', now()) - interval '90 day' or auth_user.last_login >= date_trunc('day', now()) - interval '90 day' )) as company_active_teams_last_90_days, 

(select count(*) from company_companyconnection where company_companyconnection.supplier_id = companies_company.id AND company_companyconnection.is_active = 'true' ) as as_supplier_companies_connected_to,
(select count(*) from company_companyconnection where company_companyconnection.dealer_id = companies_company.id AND company_companyconnection.is_active = 'true' ) as as_dealer_companies_connected_to,


(select count(*) from companies_trainingunit where companies_trainingunit.company_id = companies_company.id AND  companies_trainingunit.deactivated is null) as active_channels_owned_by_this_company   ,
(select count(distinct companies_sharedtrainingunit.company_id) from companies_sharedtrainingunit,companies_trainingunit where companies_trainingunit.company_id = companies_company.id AND  companies_trainingunit.deactivated is null and companies_sharedtrainingunit.training_unit_id = companies_trainingunit.id and companies_sharedtrainingunit.is_active = 'true' ) as distinct_companies_connected_to_this_companies_channels,
(select count(*) from companies_sharedtrainingunit where companies_sharedtrainingunit.company_id = companies_company.id AND companies_sharedtrainingunit.is_active = 'true' ) as channels_this_company_is_connected_to,

(select count(*) from modules_module where modules_module.company_id = companies_company.id) as total_lessons_created_by_this_company,
(select count(*) from modules_module where modules_module.company_id = companies_company.id and  (modules_module.created >= date_trunc('day', now()) - interval '90 day')) as lessons_created_last_90_days_by_this_company,

(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.user_company_id = companies_company.id) as total_lesson_attempts_by_this_company,
(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.user_company_id = companies_company.id and analytics_moduleattemptanalyticsview.is_successful ='true') as total_successful_lesson_attempts_by_this_company,

(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.user_company_id = companies_company.id and  (analytics_moduleattemptanalyticsview.created >= date_trunc('day', now()) - interval '90 day')) as lesson_attempts_last_90_days_by_this_company,
(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.user_company_id = companies_company.id and  analytics_moduleattemptanalyticsview.is_successful ='true' and (analytics_moduleattemptanalyticsview.created >= date_trunc('day', now()) - interval '90 day')) as successful_lesson_attempts_last_90_days_by_this_company,

(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.module_company_id = companies_company.id) as lessons_created_by_this_company_attempted_by_connected_companies,
(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.module_company_id = companies_company.id and analytics_moduleattemptanalyticsview.is_successful = 'true') as lessons_created_by_this_company_successfully_attempted_by_connected_companies,

(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.module_company_id = companies_company.id and (analytics_moduleattemptanalyticsview.created >= date_trunc('day', now()) - interval '90 day')) as lessons_created_by_this_company_attempted_last_90_days_by_connected_companies,
(select count(*) from analytics_moduleattemptanalyticsview where analytics_moduleattemptanalyticsview.module_company_id = companies_company.id and (analytics_moduleattemptanalyticsview.created >= date_trunc('day', now()) - interval '90 day') and analytics_moduleattemptanalyticsview.is_successful = 'true') as lessons_created_by_this_company_successfully_attempted_last_90_days_by_connected_companies,

(SELECT string_agg(companies_tag.name, ', ') FROM companies_tag , company_companytag  WHERE companies_tag.id = company_companytag.tag_id and companies_company.id = company_companytag.company_id and companies_tag.category = 'industry') as industry_tags,
(SELECT string_agg(companies_tag.name, ', ') FROM companies_tag, company_companytag  WHERE companies_tag.id = company_companytag.tag_id and companies_company.id = company_companytag.company_id and companies_tag.category = 'general') as general_tags


FROM companies_company

left join company_companytag ON company_companytag.company_id = companies_company.id
left join companies_tag ON companies_tag.id = company_companytag.tag_id
    
WHERE companies_company.deactivated is null
[[and {{company_name}}]]
[[and {{office_location}}]] 
[[and {{company_type}}]]
[[and {{tags}}]]

GROUP BY companies_company.id, companies_company.name
ORDER BY companies_company.id

这里有一个步骤示例,您可以采取这些步骤来减少查询 table 的次数,从而提高性能。

您有两个单独的相关子查询命中 auth_user table,它们都具有相同的条件和一个额外的条件。

不是实现两个单独的计数,而是 outer join 到单个派生的 table,每个 company_id 计算所有行,并且还使用附加条件的条件总和

这当然是未经测试的,但希望能传达这样的想法,您可以将其应用于来自同一 table.

的多个计数的其他情况

如果您需要额外的相关性,那么您可以使用 lateral join.

而不是派生的 table

我还使用简短、有意义的别名来使查询尽可能简洁易读。

select cc.id as company_id, cc.name as company_name...
  uc.company_user_count, uc.company_active_users_last_90_days
...
from companies_company cc
left join company_companytag cct on cct.company_id = cc.id
left join companies_tag ct on ct.id = cct.tag_id
left join (
    select u.company_id, Count(*) company_user_count,
    sum (case when (u.last_activity >= date_trunc('day', now()) - interval '90 day' or u.last_login >= date_trunc('day', now()) - interval '90 day' ) then 1 end) company_active_users_last_90_days
    from auth_user u 
    where 
        and (u.is_staff = 'false' or u.is_parent_company_admin ='false' or u.is_superuser = 'false') 
        and u.email not ilike '%fake.com%' 
        and u.email not ilike '%demo.com%'
    group by u.company_id
) uc on uc.company_id = cc.Id