4

私は PostgreSQL のインデックス作成をよりよく理解し始めていますが、クエリを高速化するためにインデックスを最適化する方法がわからない OR 条件で問題に遭遇しました。

個別に実行すると、コストが低いように見える 6 つの条件があります。クエリ プランの計算時間を含む、トリミングされたクエリの例を次に示します。

(注: 複雑さを軽減するために、これらのクエリの実際のクエリ プランを以下に出力していませんが、適切なインデックス作成で期待されるように、すべてがnested loop left joinsandを使用します。必要に応じて、より意味のある応答のためにクエリ プランを含めることができます。 index scans. )

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions1)
 LIMIT 10;

QUERY PLAN
-------------------------------------------------------------------------------------
Limit  (cost=0.25..46.69 rows=1 width=171) (actual time=0.031..0.031 rows=0 loops=1)

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions2)
 LIMIT 10;

QUERY PLAN
-------------------------------------------------------------------------------------
Limit  (cost=0.76..18.97 rows=1 width=171) (actual time=14.764..14.764 rows=0 loops=1)

/* snip */

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions6)
 LIMIT 10;

QUERY PLAN
-------------------------------------------------------------------------------------
Limit  (cost=0.51..24.48 rows=1 width=171) (actual time=0.252..5.332 rows=10 loops=1)

私の問題は、これらの 6 つの条件を OR 演算子で結合して、各条件を可能にしたいということです。結合されたクエリは次のようになります。

EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions1 OR conditions2 OR conditions3 OR conditions4 OR conditions5 OR conditions 6)
 LIMIT 10;

残念ながら、これによりクエリ プランが大幅に増加し、インデックスを使用していないように見えます (代わりに、 ahash left joinではなく aを実行することを選択し、以前に使用された に対してnested loop left joinさまざまな実行を行います)。sequence scansindex scans

Limit  (cost=142.62..510755.78 rows=1 width=171) (actual time=30.591..30.986 rows=10 loops=1)

最終的なクエリを改善する OR 条件に関してインデックス作成について知っておくべき特別なことはありますか?

UPDATE :個々の SELECT ごとに UNION を使用すると、クエリが高速化されるようです。ただし、将来的に選択した場合、結果を注文できなくなりますか? UNION を介してクエリを高速化するために行ったことは次のとおりです。

EXPLAIN ANALYZE
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions1)
UNION
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions2)
UNION
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions3)
UNION
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions4)
UNION
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions5)
UNION
SELECT t1.*, t2.*, t3.*
  FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
 WHERE (conditions6)
 LIMIT 10;

QUERY PLAN
-------------------------------------------------------------------------------------
Limit  (cost=219.14..219.49 rows=6 width=171) (actual time=125.579..125.653 rows=10 loops=1)
4

2 に答える 2

2

(申し訳ありませんが、返信に返信する方法がわからないため、これはトップ レベルになります)

明確にするために-PGは、単一のテーブルスキャンに対して単一のインデックスのみを使用していました。3 つのテーブルを結合するクエリがあり、それぞれに有用なインデックスがある場合、常に 3 つすべてを使用するのに十分スマートです。

あなたの特定のケースでは、おそらく起こっているのは、ORed 条件の間に何らかの関係があるということです。PostgreSQL はこれを認識していないため、実際よりも多くの行に一致すると想定してしまいます。クエリプランを変更するのに十分な行。

また、UNIONで結果セット全体を制限するのではなく、小さなクエリを個別に制限するため、UNIONedクエリは個々のクエリとまったく同じではありません。

UNION クエリの結果を並べ替えることができるはずですが、括弧を使用して、その ORDER BY がチェーン内の最後のサブクエリだけでなく、UNION の結果に適用されることを指定する必要があります。

これは正しくありません。ORDER BY は結果全体に適用されます。

HTH

于 2009-11-06T15:39:23.487 に答える