1

postgresql に奇妙な問題があります。プランナーは、外部キー インデックスを介したデータへのアクセスが非常に遅いと判断し、シーケンシャル スキャンを使用します。

単純化されたテーブル構造があります。

create table flight
(
    id        bigint not null constraint flight_pkey        primary key,
    parent_id bigint not null constraint flight_parent_fkey references flight
);

create table passenger
(
    id        bigint not null constraint passenger_pkey     primary key,
    flight_id bigint not null constraint pax_flight_fkey    references flight
);

create index pax_flight_id on passenger (flight_id);

テーブルpassengerには約 1,400 万行、テーブル フライトには約 6 万行あります。

問題は、多くのオプション条件を含む QueryDSL クエリがあり、そのうちの 1 つが乗客をフライトでフィルタリングすることです。

QPassenger qPassenger = QPassenger.passenger;
Long flightId = 123456;
...

BooleanBuilder predicate = new BooleanBuilder();
predicate.and(qPassenger.flight.id.eq(flightId));

...

そして、これらのオプションの条件に適合するすべての乗客を取得しようとすると、以下のようなクエリが生成され、30 秒間実行されます。それは恐ろしいです。passengerどういうわけか、すべてのテーブルに対して順次スキャンとハッシュ結合を使用します。

select
    passenger0_.id        as id1_13_,
    passenger0_.flight_id as flight_14_13_
from
    passenger passenger0_ cross join flights flight1_
where
    passenger0_.flight_id = 123456
 or flight1_.parent_id = 123456

ただし、解決策を探して 1 日を過ごした後、flightテーブルの主キーを使用すると、postgres が主キー インデックスを使用することがわかりました。

select
    passenger0_.id        as id1_13_,
    passenger0_.flight_id as flight_14_13_
from
    passenger passenger0_ cross join flights flight1_
where
    flight1_.id = 123456            --  ←this line!
 or flight1_.parent_id = 123456

残念ながら、手動で受け取った行をフィルター処理することはできません。これは、 が設定されている場合、1 フライトあたり約 300 人の乗客に対して、約 1,300 万行になるためflightIdです。

➥ それで、私の質問は次のとおりです: この条件に特定の列を使用するように QueryDSL/Hibernate に指示する方法はありますか? つまりflight.id、そうではありませんpassenger.flight_id

または、別の質問: PostgreSQL プランナーの何が問題なのですか?どうすれば修正できますか?


UPDプランナーの計画:

  • WHERE 条件で主キーを使用する適切なクエリ:
EXPLAIN ANALYZE
SELECT *
  FROM passenger p JOIN flights f ON p.flight_id = f.id
 WHERE (f.id = 123456
     OR f.parent_id = 123456);
QUERY PLAN
Nested Loop  (cost=3.66..1759.26 rows=310 width=951) (actual time=0.044..0.242 rows=184 loops=1)
  ->  Bitmap Heap Scan on flights f  (cost=3.10..9.78 rows=6 width=240) (actual time=0.024..0.029 rows=4 loops=1)
        Recheck Cond: ((id = 123456) OR (parent_id = 123456))
        Heap Blocks: exact=4
        ->  BitmapOr  (cost=3.10..3.10 rows=6 width=0) (actual time=0.018..0.018 rows=0 loops=1)
              ->  Bitmap Index Scan on flights_pkey  (cost=0.00..1.53 rows=1 width=0) (actual time=0.008..0.008 rows=1 loops=1)
                    Index Cond: (id = 123456)
              ->  Bitmap Index Scan on flt_parent_id_index  (cost=0.00..1.56 rows=5 width=0) (actual time=0.009..0.009 rows=3 loops=1)
                    Index Cond: (parent_id = 123456)
  ->  Index Scan using passenger_flight_id on passenger p  (cost=0.56..286.73 rows=485 width=711) (actual time=0.005..0.023 rows=46 loops=4)
        Index Cond: (flight_id = f.id)
Planning Time: 0.566 ms
Execution Time: 0.321 ms
  • WHERE 条件で外部キーを使用する不適切なクエリ:
EXPLAIN ANALYZE
SELECT *
  FROM passenger p JOIN flights f ON p.flight_id = f.id
 WHERE (p.flight_id = 123456
     OR f.parent_id = 123456);
QUERY PLAN
Gather  (cost=34194.96..3461993.92 rows=734 width=951) (actual time=79878.815..80711.129 rows=184 loops=1)
  Workers Planned: 2
  Workers Launched: 2
  ->  Parallel Hash Join  (cost=33194.96..3460920.52 rows=306 width=951) (actual time=71883.434..72044.345 rows=61 loops=3)
        Hash Cond: (p.flight_id = f.id)
        Join Filter: ((p.flight_id = 123456) OR (f.parent_id = 123456))
        Rows Removed by Join Filter: 11206038
        ->  Parallel Seq Scan on passenger p  (cost=0.00..827052.82 rows=14216282 width=711) (actual time=20.021..27298.757 rows=11206100 loops=3)
        ->  Parallel Hash  (cost=20891.65..20891.65 rows=275065 width=240) (actual time=1284.916..1284.917 rows=219796 loops=3)
              Buckets: 8192  Batches: 128  Memory Usage: 1248kB
              ->  Parallel Seq Scan on flights f  (cost=0.00..20891.65 rows=275065 width=240) (actual time=2.134..966.560 rows=219796 loops=3)
Planning Time: 0.605 ms
Execution Time: 80711.774 ms
4

0 に答える 0