我正在处理触及四个表的查询。该模式在以下ER模型中绘制:http://i.stack.imgur.com/FTSCJ.jpg
我尝试编写查询以返回其文件大小总和不超过关联计划存储限制的所有网站。换句话说,一旦有可用存储空间,我想知道能够创建新文件的网站。
诀窍在于,合同规划可以包含许多可以拥有多个文件的网站,因此一旦一个网站超出限制,所有共享相同合同规划的网站也必须被禁用。
经过多次尝试,我得到了以下SQL:
SELECT sites
FROM plans AS p
INNER JOIN (
SELECT cp.plan_id AS plan_id, cp.id AS contracted_plan_id, array_agg(s.id) AS sites, SUM(total_size) AS total
FROM contracted_plans AS cp
INNER JOIN sites AS s ON cp.id = s.contracted_plan_id
LEFT JOIN LATERAL(
SELECT SUM(size) AS total_size
FROM files AS f
WHERE f.site_id = s.id
) AS agg ON TRUE
GROUP BY cp.id, cp.plan_id
) AS total_per_contracted_plan
ON p.id = total_per_contracted_plan.plan_id
WHERE total < p.storage_limit;
目前这个SQL似乎有效,但我注意到它表现不佳。
我已经使用大约20万个合同计划,20万个站点(每个合同计划一个)和大约3kk文件(每个站点15个文件)填充数据库。只有5个计划,因此我将每个签约计划与随机计划相关联。
所有PK和FK都有索引。我使用的是PostgreSQL,最新版本。
使用EXPLAIN ANALYZE
表演我得到了这个:http://chunk.io/f/01c42c8aba7b414dbd8bff0299fbe84b。这花了将近4秒才完成,这似乎过分了。
如何提高SQL的性能?
答案 0 :(得分:0)
小提琴 - http://sqlfiddle.com/#!15/ce190/6/0
select distinct site_id
from (select s.id as site_id,
p.id as plan_id,
p.storage_limit,
sum(f.size) over(partition by s.id) as tot_site
from sites s
join files f
on f.site_id = s.id
join contracted_plans cp
on cp.id = s.contracted_plan_id
join plans p
on p.id = cp.plan_id) x
where tot_site < storage_limit