2017-12-19 20 views
1

私はいくつかのフライト(〜3ミル)といくつかの集計フライト(〜15ミル)を持っていますが、今はaggregated_flightsに存在しないフライトをしたいです。私は、ステータス-句を省略した場合、クエリは非常に高速であるwhere句に非常に共通の値を使用するとクエリが遅くなる

select 
    f.id 
from 
    flights f left join 
    aggregated_flights af on af.flight_id = f.id 
where 
    af.flight_id is null and 
    f.status = 'COMMITED' 
; 

が、私はそれが含まれている場合、クエリ:

は今、私はこのクエリで最高のパフォーマンスを得るためにどのように思ったんだけど1~2分かかります。ステータス欄の

値は便

私はこのような部分インデックスを作成したの〜99%のための「コミット」されています

create index on flights (id) where status = 'COMMITED'; 

しかし、効果がないようです - クエリはまだ非常に遅いです。

ここで推奨されるものは何ですか?

app=> analyze verbose flights; 
INFO: analyzing "public.flights" 
INFO: "flights": scanned 30000 of 80606 pages, containing 1161009 live rows and 0 dead rows; 30000 rows in sample, 3122535 estimated total rows 
ANALYZE 

出力を説明:分析

app=> show autovacuum; 
autovacuum 
------------ 
on 
(1 row) 

app=> \d flights 
              Table "public.flights" 
     Column  |   Type    |      Modifiers      
----------------------+-----------------------------+------------------------------------------------------ 
id     | integer      | not null default nextval('flights_id_seq'::regclass) 
name     | character varying   | 
aircraft_id   | integer      | 
status    | character varying   | 
departure_airport_id | integer      | 
arrival_airport_id | integer      | 
departure_time  | timestamp without time zone | 
off_block   | timestamp without time zone | 
arrival_time   | timestamp without time zone | 
on_block    | timestamp without time zone | 
radiation_amount  | numeric(10,6)    | 
total_day_minutes | integer      | 
total_night_minutes | integer      | 
total_instr_minutes | integer      | 
approach_type_id  | integer      | 
note     | character varying   | 
created_at   | timestamp without time zone | 
updated_at   | timestamp without time zone | 
flight_type_id  | integer      | 
owner_id    | integer      | 
night_landing  | boolean      | 
load_filename  | character varying   | 
recalc    | boolean      | 
Indexes: 
    "flights_pkey" PRIMARY KEY, btree (id) 
    "flights_id_idx" btree (id) WHERE status::text = 'COMMITED'::text 
    "index_flights_combined" btree (name, departure_airport_id, off_block) 
    "index_flights_on_aircraft_id" btree (aircraft_id) 
    "index_flights_on_approach_type_id" btree (approach_type_id) 
    "index_flights_on_arrival_airport_id" btree (arrival_airport_id) 
    "index_flights_on_created_at" btree (created_at) 
    "index_flights_on_departure_airport_id" btree (departure_airport_id) 
    "index_flights_on_flight_type_id" btree (flight_type_id) 
    "index_flights_on_off_block" btree (off_block) 
    "index_flights_on_on_block" btree (on_block) 
    "index_flights_on_owner_id" btree (owner_id) 

自動バキューム:

テーブル定義(Postgresqlの9.4及び9.6に経験)

app=> explain (analyze, buffers) select f.id from flights f left join aggregated_flights af on af.flight_id = f.id where af.flight_id is null and f.status = 'COMMITED' limit 100; 

Limit (cost=7.25..68.59 rows=100 width=4) (actual time=58744.490..58744.604 rows=100 loops=1) 
    Buffers: shared hit=367361 read=248982 
    -> Merge Anti Join (cost=7.25..1829081.46 rows=2981880 width=4) (actual time=58744.489..58744.586 rows=100 loops=1) 
     Merge Cond: (f.id = af.flight_id) 
     Buffers: shared hit=367361 read=248982 
     -> Index Scan using flights_id_idx on flights f (cost=0.43..743949.15 rows=3106090 width=4) (actual time=0.066..24170.693 rows=3106983 loops=1) 
       Buffers: shared hit=316162 read=85698 
     -> Index Only Scan using index_aggregated_flights_on_flight_id_and_flight_relation_id on aggregated_flights af (cost=0.56..886207.11 rows=15357503 width=4) (actual time=0.014..31282.777 rows=15360252 loops=1) 
       Heap Fetches: 0 
       Buffers: shared hit=51199 read=163284 
Planning time: 246.341 ms 
Execution time: 58744.695 ms 

更新私はちょうどflight_idに、aggregated_flightsテーブルにインデックスを追加しました。これは間違いなくクエリーを速くしましたが、私はまだ10秒は少しだと思います。結合列上の2つの索引を持つ

app=> explain (analyze, buffers) select f.id from flights f left join aggregated_flights af on af.flight_id = f.id where af.flight_id is null and f.status = 'COMMITED' limit 1000; 
                          QUERY PLAN                       
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=3.83..453.80 rows=1000 width=4) (actual time=9986.052..9986.508 rows=470 loops=1) 
    Buffers: shared hit=365265 read=126777 
    -> Merge Anti Join (cost=3.83..1341784.78 rows=2981880 width=4) (actual time=9986.050..9986.437 rows=470 loops=1) 
     Merge Cond: (f.id = af.flight_id) 
     Buffers: shared hit=365265 read=126777 
     -> Index Scan using flights_id_idx on flights f (cost=0.43..743949.15 rows=3106090 width=4) (actual time=0.935..3891.800 rows=3107353 loops=1) 
       Buffers: shared hit=317084 read=84797 
     -> Index Only Scan using aggregated_flights_flight_id_idx on aggregated_flights af (cost=0.43..398876.22 rows=15360252 width=4) (actual time=0.023..3270.955 rows=15360252 loops=1) 
       Heap Fetches: 0 
       Buffers: shared hit=48181 read=41980 
Planning time: 53.676 ms 
Execution time: 9986.603 ms 
(12 rows) 
+0

両方のクエリでEXPLAIN ANALYZEの出力を提供できますか? – Eelke

+0

@eelkeはい、もちろん - 質問に追加しました – henrik242

+1

これは単純な 'explain'出力です。' explain(analyze、buffers) 'によって提供される情報がもっと役に立ちます。 –

答えて

1

、そのうちの一つが、部分的WHERE条件に対応するために、あなたは、可能な限り多くのクエリの速度を向上しました。

PostgreSQL側の唯一の改善点は、インデックスのみの部分インデックスのです。そのためには、VACUUM flightsを使用し、PostgreSQL 9.6以降を使用する必要があります。ここでは、部分インデックスのみでインデックスをスキャンできます。

それ以外の最適な最適化では、ディスク全体のデータをディスクから読み取る必要がないように、データベース全体(または少なくとも関連するインデックス)をキャッシュするのに十分なRAMをマシンに与えます。 pg_prewarmを使用して、テーブルまたはインデックスをキャッシュに読み込むことができます。

+0

多分私は質問を更新するときに間違いを犯しました。今は正しいはずです。また、自動バキューム設定をチェックし、分析を実行しました。それは今はっきりしていますか? – henrik242

+0

それは正しく見えません。実行計画で 'f.status = 'COMMITED'という条件が表示されません。 –

+0

あなたは正しいですが、それは私が得る出力です。それはインデックス 'flights_id_idx'を使っていますが、これは私が作成した部分的なインデックスなので、それが適用されていると思います。 – henrik242