2016-03-27 16 views
0

私はPostgresで2つのテーブル結合を使用して比較的控えめなクエリを持っていますが、開発環境と本番環境の両方でクエリを実行すると大幅にパフォーマンスが向上しています。PostgreSQLがクエリプランを選択する理由を判断するにはどうすればよいですか?

これはクエリです:インデックスがそうであるように2つの環境で

select count(seat_id) as avail, ev.event_name, price_code, 
    (case when substring(section_name, 4, 1) = 'A' then substring(section_name, 1, 3) 
     when row_name < '9999' then section_name 
     else section_name || 'C' 
    end) as section_name_full, class_name 
from tm_availseats3_exp seats join tm_event_map ev on ev.event_name = seats.event_name 
where event_sub_type = 'General' 
group by ev.event_name, price_code, section_name_full, class_name, row_name 

データは、同じです。両方の環境で両方のクエリを「Analyze Explain」で実行し、以下の結果を得ました。

これは速いです:

HashAggregate (cost=29061.69..29229.88 rows=7475 width=41) (actual time=662.006..682.448 rows=17444 loops=1) 
    Group Key: ev.event_name, seats.price_code, CASE WHEN ("substring"((seats.section_name)::text, 4, 1) = 'A'::text) THEN "substring"((seats.section_name)::text, 1, 3) WHEN ((seats.row_name)::text < '9999'::text) THEN (seats.section_name)::text ELSE ((seats.section_name)::text || 'C'::text) END, seats.class_name, seats.row_name 
-> Nested Loop (cost=1090.79..28949.57 rows=7475 width=41) (actual time=2.267..488.597 rows=110977 loops=1) 
    -> HashAggregate (cost=784.42..784.44 rows=1 width=51) (actual time=2.076..2.163 rows=61 loops=1) 
      Group Key: ev_1.event_name, ev.event_name, ev_1.event_date, ev.event_name_long, ev.event_time, ev.event_day, CASE WHEN ("substring"((ev.event_name)::text, 1, 4) = 'EUCB'::text) THEN 'General'::text ELSE 'Premium'::text END 
      -> Nested Loop (cost=558.96..784.41 rows=1 width=51) (actual time=0.997..1.967 rows=61 loops=1) 
       -> HashAggregate (cost=558.68..558.78 rows=10 width=12) (actual time=0.953..1.021 rows=61 loops=1) 
         Group Key: ev_1.event_name, ev_1.event_date 
         -> Seq Scan on tm_evnt3 ev_1 (cost=0.00..558.63 rows=10 width=12) (actual time=0.035..0.876 rows=61 loops=1) 
          Filter: ("substring"((event_name)::text, 1, 4) = 'EUCB'::text) 
          Rows Removed by Filter: 1981 
       -> Index Scan using idx_tm_evnt3__event_date on tm_evnt3 ev (cost=0.28..22.54 rows=1 width=43) (actual time=0.006..0.011 rows=1 loops=61) 
         Index Cond: (event_date = ev_1.event_date) 
         Filter: (("substring"((event_name)::text, 1, 4) <> 'PARK'::text) AND ("substring"((event_name)::text, 1, 5) <> 'PROMO'::text) AND ("substring"((event_name)::text, length((event_name)::text), 1) <> 'P'::text) AND (CASE WHEN ("substring"((event_name)::text, 1, 4) = 'EUCB'::text) THEN 'General'::text ELSE 'Premium'::text END = 'General'::text)) 
         Rows Removed by Filter: 5 
    -> Bitmap Heap Scan on tm_availseats3_exp seats (cost=306.36..27996.93 rows=7475 width=41) (actual time=0.194..2.352 rows=1819 loops=61) 
      Recheck Cond: ((event_name)::text = (ev.event_name)::text) 
      Heap Blocks: exact=12875 
      -> Bitmap Index Scan on tm_availseats3_exp_on_event (cost=0.00..304.50 rows=7475 width=0) (actual time=0.168..0.168 rows=1819 loops=61) 
       Index Cond: ((event_name)::text = (ev.event_name)::text) 
Planning time: 0.498 ms 
Execution time: 700.538 ms 

そして、これは、本当に遅いです:

HashAggregate (cost=1083030.39..1083267.27 rows=10528 width=41) (actual time=107897.847..107918.705 rows=17444 loops=1) 
    Group Key: ev.event_name, seats.price_code, CASE WHEN ("substring"((seats.section_name)::text, 4, 1) = 'A'::text) THEN "substring"((seats.section_name)::text, 1, 3) WHEN ((seats.row_name)::text < '9999'::text) THEN (seats.section_name)::text ELSE ((seats.section_name)::text || 'C'::text) END, seats.class_name, seats.row_name 
    -> Hash Join (cost=795.21..1082872.47 rows=10528 width=41) (actual time=47773.210..107704.968 rows=110977 loops=1) 
    Hash Cond: ((seats.event_name)::text = (ev.event_name)::text) 
    -> Seq Scan on tm_availseats3_exp seats (cost=0.00..1052862.73 rows=7727373 width=41) (actual time=3352.769..103536.131 rows=3609106 loops=1) 
    -> Hash (cost=795.20..795.20 rows=1 width=8) (actual time=2.364..2.364 rows=61 loops=1) 
      Buckets: 1024 Batches: 1 Memory Usage: 3kB 
      -> Subquery Scan on ev (cost=795.18..795.20 rows=1 width=8) (actual time=2.107..2.292 rows=61 loops=1) 
       -> HashAggregate (cost=795.18..795.19 rows=1 width=51) (actual time=2.104..2.169 rows=61 loops=1) 
         Group Key: ev_2.event_name, ev_1.event_name, ev_2.event_date, ev_1.event_name_long, ev_1.event_time, ev_1.event_day, CASE WHEN ("substring"((ev_1.event_name)::text, 1, 4) = 'EUCB'::text) THEN 'General'::text ELSE 'Premium'::text END 
         -> Nested Loop (cost=568.96..795.16 rows=1 width=51) (actual time=0.998..1.987 rows=61 loops=1) 
          -> HashAggregate (cost=568.68..568.78 rows=10 width=12) (actual time=0.942..1.018 rows=61 loops=1) 
            Group Key: ev_2.event_name, ev_2.event_date 
            -> Seq Scan on tm_evnt3 ev_2 (cost=0.00..568.63 rows=10 width=12) (actual time=0.039..0.864 rows=61 loops=1) 
             Filter: ("substring"((event_name)::text, 1, 4) = 'EUCB'::text) 
             Rows Removed by Filter: 1981 
          -> Index Scan using idx_tm_evnt3__event_date on tm_evnt3 ev_1 (cost=0.28..22.62 rows=1 width=43) (actual time=0.006..0.011 rows=1 loops=61) 
            Index Cond: (event_date = ev_2.event_date) 
            Filter: (("substring"((event_name)::text, 1, 4) <> 'PARK'::text) AND ("substring"((event_name)::text, 1, 5) <> 'PROMO'::text) AND ("substring"((event_name)::text, length((event_name)::text), 1) <> 'P'::text) AND (CASE WHEN ("substring"((event_name)::text, 1, 4) = 'EUCB'::text) THEN 'General'::text ELSE 'Premium'::text END = 'General'::text)) 
            Rows Removed by Filter: 5 
Planning time: 0.482 ms 
Execution time: 107936.927 ms 

問題は第2の実行計画は、配列をスキャンして、クエリを開始することであると私にはかなり明らかですここに含まれる2つのテーブルの中ではるかに大きなものが何であるかについては分かりませんが、なぜ同じプランを作成しないのか分かりません。

Postgresクエリプランナーは決定的ですか?クエリプランを使用する際のヒントを提供する方法はありますか?

+1

「遅い」マシン上に 'tm_availseats3_exp_on_event'インデックスが作成されているかどうかを確認し、作成されていない場合は作成し、再度Explain分析を実行してください。 – krokodilko

+2

クエリに表示される各テーブルに対して 'VACUUM ANALYZE ;'を実行してください。 –

+0

VACUUM ANALYZEを使用するのが正しい戦略でした。ありがとう! – TWAndrews

答えて

1

Ildar Musinがコメントしたように、正しい方法は、すべてのデータベースで統計情報が最新であることを確認することです。私の理解では、これは自動的に起こっていたが、そうではなかった。

VACUUM ANALYZEは、実行速度の遅いクエリのパフォーマンスを高速なクエリのパフォーマンスに非常に近づけることができました。

関連する問題