我有更多关于Joining many-to-many relationships的问题,但我认为最好问一个新问题。
完整查询:
SELECT p.id
,(100 * sum((a.price > 0)::int)) / cc.ct AS commercial
,(100 * sum((a.price = 0)::int)) / cf.ct AS free
FROM (SELECT count(*)::float AS ct FROM applications WHERE price > 0) AS cc
,(SELECT count(*)::float AS ct FROM applications WHERE price = 0) AS cf
,permissions p
LEFT JOIN applications_permissions ap ON ap.permission_id = p.id
LEFT JOIN applications a ON a.id = ap.application_id
GROUP BY 1, cc.ct, cf.ct
ORDER BY 2 DESC, 3 DESC, 1;
关于执行时间:
SELECT p.id
->总运行时间:2467.801ms
SELECT (SELECT regex FROM permissions WHERE id = p.id) AS regex
->总运行时间:28882.293ms
这里发生了什么事?
正确的方法是什么?
选择p.id
QUERY PLAN
Sort (cost=123257.63..123258.07 rows=178 width=24)
Sort Key: (((sum(((a.price > 0::double precision))::integer))::double precision / ((count(*))::double precision))), (((sum(((a.price = 0::double precision))::integer))::double precision / ((count(*))::double precision))), p.id
-> HashAggregate (cost=123244.74..123250.97 rows=178 width=24)
-> Hash Left Join (cost=53709.64..115103.31 rows=651315 width=24)
Hash Cond: (ap.application_id = a.id)
-> Hash Left Join (cost=42222.11..82232.48 rows=651315 width=24)
Hash Cond: (p.id = ap.permission_id)
-> Nested Loop (cost=18283.65..18305.06 rows=178 width=20)
-> Index Scan using permissions_pkey on permissions p (cost=0.00..17.85 rows=178 width=4)
Filter: (regex IS NOT NULL)
-> Materialize (cost=18283.65..18283.66 rows=1 width=16)
-> Nested Loop (cost=18283.60..18283.65 rows=1 width=16)
-> Aggregate (cost=9016.51..9016.52 rows=1 width=0)
-> Seq Scan on applications (cost=0.00..8915.85 rows=40262 width=0)
Filter: (price > 0::double precision)
-> Aggregate (cost=9267.09..9267.10 rows=1 width=0)
-> Seq Scan on applications (cost=0.00..8915.85 rows=140494 width=0)
Filter: (price = 0::double precision)
-> Hash (cost=11271.65..11271.65 rows=772065 width=8)
-> Seq Scan on applications_permissions ap (cost=0.00..11271.65 rows=772065 width=8)
-> Hash (cost=8453.68..8453.68 rows=184868 width=8)
-> Seq Scan on applications a (cost=0.00..8453.68 rows=184868 width=8)
22 row(s)
Total runtime: 4.524 ms
选择(选择…)
QUERY PLAN
Sort (cost=3796049.42..3796049.86 rows=178 width=24)
Sort Key: (((sum(((a.price > 0::double precision))::integer))::double precision / ((count(*))::double precision))), (((sum(((a.price = 0::double precision))::integer))::double precision / ((count(*))::double precision))), ((SubPlan 1))
-> HashAggregate (cost=3795033.06..3796042.76 rows=178 width=24)
-> Hash Left Join (cost=53709.64..3786891.62 rows=651315 width=24)
Hash Cond: (ap.application_id = a.id)
-> Hash Left Join (cost=42222.11..82232.48 rows=651315 width=24)
Hash Cond: (p.id = ap.permission_id)
-> Nested Loop (cost=18283.65..18305.06 rows=178 width=20)
-> Index Scan using permissions_pkey on permissions p (cost=0.00..17.85 rows=178 width=4)
Filter: (regex IS NOT NULL)
-> Materialize (cost=18283.65..18283.66 rows=1 width=16)
-> Nested Loop (cost=18283.60..18283.65 rows=1 width=16)
-> Aggregate (cost=9016.51..9016.52 rows=1 width=0)
-> Seq Scan on applications (cost=0.00..8915.85 rows=40262 width=0)
Filter: (price > 0::double precision)
-> Aggregate (cost=9267.09..9267.10 rows=1 width=0)
-> Seq Scan on applications (cost=0.00..8915.85 rows=140494 width=0)
Filter: (price = 0::double precision)
-> Hash (cost=11271.65..11271.65 rows=772065 width=8)
-> Seq Scan on applications_permissions ap (cost=0.00..11271.65 rows=772065 width=8)
-> Hash (cost=8453.68..8453.68 rows=184868 width=8)
-> Seq Scan on applications a (cost=0.00..8453.68 rows=184868 width=8)
SubPlan 1
-> Seq Scan on permissions (cost=0.00..5.64 rows=1 width=26)
Filter: (id = $0)
25 row(s)
Total runtime: 6.566 ms
最佳答案
看起来您正在尝试将相关子查询添加到SELECT
列表,而您可以只选择列:
SELECT p.id, p.regex
,(100 * sum((a.price > 0)::int)) / cc.ct AS commercial
,(100 * sum((a.price = 0)::int)) / cf.ct AS free
FROM (SELECT count(*)::float AS ct FROM applications WHERE price > 0) AS cc
,(SELECT count(*)::float AS ct FROM applications WHERE price = 0) AS cf
,permissions p
LEFT JOIN applications_permissions ap ON ap.permission_id = p.id
LEFT JOIN applications a ON a.id = ap.application_id
GROUP BY p.id, p.regex, cc.ct, cf.ct
ORDER BY commercial DESC, free DESC, p.id;
如果
p.id
是主键,那么它覆盖了整个表,并且从Postgres9.1开始就不必在p.regex
中添加GROUP BY
。关于sql - 加入多对多关系,执行时间,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11299416/