2013-02-20 9 views
23

サブクエリーと一緒に使用すると "IN"演算子が遅くなるのはなぜですか?サブクエリーの性能が悪いPostgreSQL IN演算子

select * 
from view1 
where id in (1,2,3,4,5,6,7,8,9,10) 
order by somedata; 

は9msで実行されます。

select * 
from view1 
where id in (select ext_id 
      from aggregate_table 
      order by somedata limit 10) 
order by somedata; 

は25000msで実行され、最初のクエリでないにようサブクエリから返された主キーのビュー(view1)の代わりに、インデックススキャンにシーケンシャルスキャンを使用しているようです。

サブクエリselect ext_id from aggregate_table order by somedata limit 10ので2番目のクエリの遅さは、3つの共用体を含むビュー であり、約3は、各UNIONに参加するview1に順次走査することによって引き起こされる

0.1msで実行されます。最初のUNIONには1M行程度のものがあり、他のものにはそれほど多くはありません。約100K行のテーブルを結合します。これはあまり意味がありませんが、IN演算子の動作を理解したかっただけです。

私が達成しようとしているのは、サブクエリ(プライマリキーのセット)の結果を受け取り、それらを使って複雑なビュー(view1)からデータを選択することです。

私は大きいがsomedataで参加ソートする必要はありませんので、私はまた

select v1.* 
from view1 v1, 
    aggregate_table at 
where v1.id = at.ext_id 
order by at.somedata 
limit 10 

を使用することはできません。私はちょうど主キーでビューから10の結果を選択し、これらのみを並べ替えたいです。

なぜ、IN演算子は明示的にこれらのキーをリストすると速く実行するのですか?まったく同じセットのキーを返す高速サブクエリを使用すると遅くなりますか? select * from view1 where id in (1,2,3,4,5,6,7,8,9,10) order by somedata;

Sort (cost=348.480..348.550 rows=30 width=943) (actual time=14.385..14.399 rows=10 loops=1) 
    Sort Key: "india".three 
    Sort Method: quicksort Memory: 30kB 
    -> Append (cost=47.650..347.440 rows=30 width=334) (actual time=11.528..14.275 rows=10 loops=1) 
     -> Subquery Scan "*SELECT* 1" (cost=47.650..172.110 rows=10 width=496) (actual time=11.526..12.301 rows=10 loops=1) 
       -> Nested Loop (cost=47.650..172.010 rows=10 width=496) (actual time=11.520..12.268 rows=10 loops=1) 
        -> Hash Join (cost=47.650..87.710 rows=10 width=371) (actual time=11.054..11.461 rows=10 loops=1) 
          Hash Cond: (hotel.alpha_five = juliet_xray.alpha_five) 
          -> Bitmap Heap Scan on sierra hotel (cost=42.890..82.800 rows=10 width=345) (actual time=10.835..11.203 rows=10 loops=1) 
            Recheck Cond: (four = ANY ('quebec'::integer[])) 
           -> Bitmap Index Scan on seven (cost=0.000..42.890 rows=10 width=0) (actual time=0.194..0.194 rows=10 loops=1) 
             Index Cond: (four = ANY ('quebec'::integer[])) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.184..0.184 rows=34 loops=1) 
           -> Seq Scan on six juliet_xray (cost=0.000..4.340 rows=34 width=30) (actual time=0.029..0.124 rows=34 loops=1) 
        -> Index Scan using charlie on juliet_two zulu (cost=0.000..8.390 rows=1 width=129) (actual time=0.065..0.067 rows=1 loops=10) 
          Index Cond: (zulu.four = hotel.victor_whiskey) 
     -> Subquery Scan "*SELECT* 2" (cost=4.760..97.420 rows=10 width=366) (actual time=0.168..0.168 rows=0 loops=1) 
       -> Hash Join (cost=4.760..97.320 rows=10 width=366) (actual time=0.165..0.165 rows=0 loops=1) 
         Hash Cond: (alpha_xray.alpha_five = juliet_xray2.alpha_five) 
        -> Nested Loop (cost=0.000..92.390 rows=10 width=340) (actual time=0.162..0.162 rows=0 loops=1) 
          -> Seq Scan on lima_echo alpha_xray (cost=0.000..8.340 rows=10 width=216) (actual time=0.159..0.159 rows=0 loops=1) 
            Filter: (four = ANY ('quebec'::integer[])) 
          -> Index Scan using charlie on juliet_two xray (cost=0.000..8.390 rows=1 width=128) (never executed) 
            Index Cond: (zulu2.four = alpha_xray.victor_whiskey) 
        -> Hash (cost=4.340..4.340 rows=34 width=30) (never executed) 
          -> Seq Scan on six uniform (cost=0.000..4.340 rows=34 width=30) (never executed) 
     -> Subquery Scan "*SELECT* 3" (cost=43.350..77.910 rows=10 width=141) (actual time=1.775..1.775 rows=0 loops=1) 
       -> Hash Join (cost=43.350..77.810 rows=10 width=141) (actual time=1.771..1.771 rows=0 loops=1) 
         Hash Cond: (golf.alpha_five = juliet_xray3.alpha_five) 
        -> Bitmap Heap Scan on lima_golf golf (cost=38.590..72.910 rows=10 width=115) (actual time=0.110..0.110 rows=0 loops=1) 
          Recheck Cond: (four = ANY ('quebec'::integer[])) 
          -> Bitmap Index Scan on victor_hotel (cost=0.000..38.590 rows=10 width=0) (actual time=0.105..0.105 rows=0 loops=1) 
            Index Cond: (four = ANY ('quebec'::integer[])) 
        -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.118..0.118 rows=34 loops=1) 
          -> Seq Scan on six victor_kilo (cost=0.000..4.340 rows=34 width=30) (actual time=0.007..0.063 rows=34 loops=1) 
Total runtime: 14.728 ms 

2番目のクエリ - - select * from view1 where id in (select ext_id from aggregate_table order by somedata limit 10) order by somedata;

Sort (cost=254515.780..254654.090 rows=55325 width=943) (actual time=24687.475..24687.488 rows=10 loops=1) 
    Sort Key: "five".xray_alpha 
    Sort Method: quicksort Memory: 30kB 
    -> Hash Semi Join (cost=54300.820..250157.370 rows=55325 width=943) (actual time=11921.783..24687.308 rows=10 loops=1) 
      Hash Cond: ("five".lima = "delta_echo".lima) 
     -> Append (cost=54298.270..235569.720 rows=1106504 width=494) (actual time=3412.453..23091.938 rows=1106503 loops=1) 
       -> Subquery Scan "*SELECT* 1" (cost=54298.270..234227.250 rows=1100622 width=496) (actual time=3412.450..20234.122 rows=1100622 loops=1) 
        -> Hash Join (cost=54298.270..223221.030 rows=1100622 width=496) (actual time=3412.445..17078.021 rows=1100622 loops=1) 
          Hash Cond: (three_victor.xray_hotel = delta_yankee.xray_hotel) 
          -> Hash Join (cost=54293.500..180567.160 rows=1100622 width=470) (actual time=3412.251..12108.676 rows=1100622 loops=1) 
            Hash Cond: (three_victor.tango_three = quebec_seven.lima) 
           -> Seq Scan on india three_victor (cost=0.000..104261.220 rows=1100622 width=345) (actual time=0.015..3437.722 rows=1100622 loops=1) 
           -> Hash (cost=44613.780..44613.780 rows=774378 width=129) (actual time=3412.031..3412.031 rows=774603 loops=1) 
             -> Seq Scan on oscar quebec_seven (cost=0.000..44613.780 rows=774378 width=129) (actual time=4.142..1964.036 rows=774603 loops=1) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.149..0.149 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo delta_yankee (cost=0.000..4.340 rows=34 width=30) (actual time=0.017..0.095 rows=34 loops=1) 
       -> Subquery Scan "*SELECT* 2" (cost=4.760..884.690 rows=104 width=366) (actual time=7.846..10.161 rows=104 loops=1) 
        -> Hash Join (cost=4.760..883.650 rows=104 width=366) (actual time=7.837..9.804 rows=104 loops=1) 
          Hash Cond: (foxtrot.xray_hotel = delta_yankee2.xray_hotel) 
          -> Nested Loop (cost=0.000..877.200 rows=104 width=340) (actual time=7.573..9.156 rows=104 loops=1) 
           -> Seq Scan on four_india foxtrot (cost=0.000..7.040 rows=104 width=216) (actual time=0.081..0.311 rows=104 loops=1) 
           -> Index Scan using three_delta on oscar alpha_victor (cost=0.000..8.350 rows=1 width=128) (actual time=0.077..0.078 rows=1 loops=104) 
             Index Cond: (quebec_seven2.lima = foxtrot.tango_three) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.216..0.216 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo quebec_foxtrot (cost=0.000..4.340 rows=34 width=30) (actual time=0.035..0.153 rows=34 loops=1) 
       -> Subquery Scan "*SELECT* 3" (cost=4.760..457.770 rows=5778 width=141) (actual time=0.264..58.353 rows=5777 loops=1) 
        -> Hash Join (cost=4.760..399.990 rows=5778 width=141) (actual time=0.253..39.062 rows=5777 loops=1) 
          Hash Cond: (four_uniform.xray_hotel = delta_yankee3.xray_hotel) 
          -> Seq Scan on whiskey four_uniform (cost=0.000..315.780 rows=5778 width=115) (actual time=0.112..15.759 rows=5778 loops=1) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.117..0.117 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo golf (cost=0.000..4.340 rows=34 width=30) (actual time=0.005..0.059 rows=34 loops=1) 
     -> Hash (cost=2.430..2.430 rows=10 width=4) (actual time=0.303..0.303 rows=10 loops=1) 
       -> Subquery Scan "ANY_subquery" (cost=0.000..2.430 rows=10 width=4) (actual time=0.092..0.284 rows=10 loops=1) 
        -> Limit (cost=0.000..2.330 rows=10 width=68) (actual time=0.089..0.252 rows=10 loops=1) 
          -> Index Scan using tango_seven on zulu romeo (cost=0.000..257535.070 rows=1106504 width=68) (actual time=0.087..0.227 rows=10 loops=1) 
Total runtime: 24687.975 ms 
+1

EXPLAIN ANALYZE SELECT ...を表示できますか?おそらく、[depesz](http://explain.depesz.com/) – MatheusOl

+0

を使用して、私は一時テーブルにサブクエリの結果を入れてみて、IN(select id from temptable)を実行します。相違点は、table1の各行に対してオプティマイザが副選択を実行する可能性のある 'limit'節です。これは@Clodoaldoと同じように思えますが、 – rootkit

+0

は、一時テーブルを作成しました。aggregate_table_tmpをselect_ext_idからsomedata_limit_limit 10で選択し、それをサブクエリの 'select * from table1で使用しています(idをselect at_id_id from aggregate_table_tmp) 〜によってsomedata' - 運がない。同じ25000ms。 – Snifff

答えて

29

私が最終的に解決策を見つけたようだ:についてはどのように

私はどこのid(1の容疑者、 2,3,4,5,6,7,8,9,10)を最適化することができます。 ここでid(select ...)はできません。その理由はです0(1,2,3,4,5,6,7,8,9,10)は定数式ですが、selectは ではありません。

と、これは1.2ms以上についての質問、最初のクエリよりもさらに速く動作します

Recheck Cond: (id = ANY ('{1,2,3,4,5,6,7,8,9,10}'::integer[])) 
Index Cond: (id = ANY ('{1,2,3,4,5,6,7,8,9,10}'::integer[])) 

速くクエリプランでこれらの場所を、今では

Recheck Cond: (id = ANY ($1)) 
Index Cond: (id = ANY ($1)) 

やビットマップスキャンを使用しています計画の中で。

+11

' ARRAY'を使うと、PGにサブクエリでインデックスを使うように指示する素晴らしいトリックです。 array(select your query)) ' –

+0

私は実験する大きなデータがありませんが、なぜ@BlueSmith' array(select ..)の代わりに 'select array(select ...)'を使うのですか? ) '?:: integer []'でも違いはありますか?たとえば、文字列値を持っている場合は、より速いパフォーマンスを得るために型をキャストする必要がありますか? – akostadinov

3
私は where id in (1,2,3,4,5,6,7,8,9,10)を最適化することができ疑い

where id in (select ...)ことはできない、その理由

最初のクエリを要求したとして、ANALYZE EXPLAINそのことは(1,2,3,4,5,6,7,8,9,10)は定数eであるxpression、selectはそうではありません。 Dukelingのアイデア@起草した後

select * 
    from view1 
    where view1.id = ANY(
         (select array(select ext_id 
            from aggregate_table 
            order by somedata limit 10) 
         )::integer[] 
        ) 
    order by view1.somedata; 

WITH myCTE AS 
(
    SELECT ext_id 
    FROM aggregate_table 
    ORDER BY somedata 
    LIMIT 10 
) 
SELECT * 
FROM myCTE 
LEFT JOIN table1 
    ON myCTE.ext_id = table1.id 
ORDER BY somedata 
+0

@ Clodoaldoの亜種と同じ24000 ms – Snifff

+0

@Snifff「LEFT JOIN」に変更されても差はあるかもしれません。要するに、PostgreSQLは最適化の際にひどい仕事をしているようですが、同じデータに対してMySQLまたはSQL Serverのパフォーマンスを見たいと思います。 – Dukeling

+2

'LEFT JOIN'は65000msまでの時間差を作っています:( – Snifff

関連する問題