我有更多关于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/

10-10 03:01