加入多对多关系,执行时间

时间:2012-07-02 18:47:23

标签: sql postgresql

我对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

- >总运行时间:2,467.801 ms

SELECT (SELECT regex FROM permissions WHERE id = p.id) AS regex

- >总运行时间:28,882.293 ms

这里发生了什么? 这样做的正确方法是什么?

SELECT 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

SELECT(SELECT ...)

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

1 个答案:

答案 0 :(得分:1)

看起来您正在尝试将相关子查询添加到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是主键,则它涵盖整个表格,因为Postgres 9.1,您不必在p.regex中添加GROUP BY