0

そんな問い合わせが来ました

SELECT DISTINCT p.id 
FROM person p 
    INNER JOIN person_func pf1 
        ON p.id = pf1.person_id 
    INNER JOIN Func f1 
        ON f1.id = pf1.func_id
    LEFT JOIN person_location pf2 
        ON p.id = pf2.person_id 
    LEFT JOIN Location f2 
        ON f2.id = pf2.location_id AND f2.val='1'
    LEFT JOIN person_location pf3 
        ON p.id = pf3.person_id 
    LEFT JOIN Location f3 
        ON f3.id = pf3.location_id and f3.val='3'
WHERE f2.val IS NOT NULL OR f3.val IS NOT NULL;

そして、共通して、このような 9 ~ 10 の結合があります。そして、それは非常に遅く実行されます。person_func(person_id)、person_location(person_id) にインデックスを追加しましたが、役に立ちませんでした。最適化するにはどうすればよいですか?

例 - SQLFiddle の例

4

2 に答える 2

1

テーブルの ~ 5% を超える場合val IS NOT NULL(その可能性が非常に高い)、インデックス onはには役に立ちvalません。WHERE

ただし、特定の値で結合する JOIN 句で役立つ場合があります。ただし、さらに良い: 複数列のインデックス:

CREATE INDEX some_name_idx ON Location (location_id, val)

特定の状況 (特に、val = 1val = 3まれな場合) によっては、部分インデックスがさらに役立つ場合があります。

CREATE INDEX some_name1_idx ON Location (location_id)
WHERE val = 1

CREATE INDEX some_name3_idx ON Location (location_id)
WHERE val = 3

それ以外に、使用される値が一般的でない場合 (テーブルの ~ 5% 未満)、JOIN または WHERE 条件で使用されるすべての列にインデックスが必要です。通常、これは当てはまります。

パフォーマンスの最適化に関する通常のアドバイスがすべて適用されます。

より具体的なアドバイスが必要な場合は、多くの情報を投稿する必要があります。タグ wikiを読んでください。

非常に多くのテーブルに参加しているため、Postgres が最適なプランを見つけられない (考えられるバリエーションが多すぎる) 制限を超える可能性があります。最も選択的なJOIN を最初に記述することが重要になる場合があります。この場合、通常JOINは が優先されます。詳しくはこちらのマニュアルをご覧ください。LEFT JOIN

CROSS JOIN代理人による

つまり、10 個の LEFT JOIN があります。例: それらの半分に 3 つの一致がある場合、行数に 3^5 = 243 を掛けます。または、それらすべてに 5 つの一致がある場合、5^10 = 9765625 を掛けます。これはひどいパフォーマンスにつながります。そして、あなたは最終的に欲しいだけなので、すべて無料ですDISTINCT id

ケーキのアイシング: を取得するにDISTINCT person.idは、これらの LEFT JOIN はすべて 100% 役に立ちません。彼らは何も変えません。それらをすべて削除してください。

について:行の乗算を避けるために、JOINそれらを に置き換えます。EXISTSお気に入り:

EXISTS (SELECT 1 FROM Func f1 WHERE f1.id = pf1.func_id)
于 2013-03-26T08:15:12.757 に答える
0

WHERE 句は実際には冗長なようです。値が特定の値であることに基づいて既に結合している場合、WHERE 句はそれらの値が NULL でないことを確認するため、結合が発生したことを確認するだけです。したがって、結合が発生した行のみを取得する場合は、LEFT JOIN ではなく INNER JOIN を使用できます。==> f2.val は、LEFT JOIN が発生しなかった場合にのみ null になります。

LEFT JOIN Location f2 ON f2.id = pf2.location_id AND f2.val='1'

f2.valが NULL でない場合

したがって、この場合はおそらく内部結合を試すことができます。

必要な値に対応する ID を識別し、代わりにそれらに結合することもできます。これらは主キーになり、はるかに効率的になります。

本当の問題を特定する

また、各結合を 1 つずつ取り出してクエリを再実行し、毎回時間が短縮されることに注意することをお勧めします。これにより、どの結合要素または句要素が問題を引き起こしているかがわかります。

  1. クエリをそのまま実行します。
  2. 最初の where 句の式を削除します。
  3. 2 番目の where 句の式を削除します。
  4. 結合を 1 つ削除する
  5. 別の結合を削除...
于 2013-03-26T16:31:47.400 に答える