web-dev-qa-db-ja.com

パフォーマンスの違い:INNER JOIN vs WHERE句に置かれた条件

orderというテーブルがあるとします

id | clientid | type | amount | itemid | date
---|----------|------|--------|--------|-----------
23 | 258      | B    | 150    | 14     | 2012-04-03
24 | 258      | S    | 69     | 14     | 2012-04-03
25 | 301      | S    | 10     | 20     | 2012-04-03
26 | 327      | B    | 54     | 156    | 2012-04-04
  • clientidclientテーブルに戻る外部キーです
  • itemiditemテーブルに戻る外部キーです
  • typeBまたはSのみです
  • amountは整数です

およびテーブルprocessed as

id | orderid | processed | date
---|---------|-----------|---------
41 | 23      | true      | 2012-04-03
42 | 24      | true      | 2012-04-03
43 | 25      | false     | <NULL>
44 | 26      | true      | 2012-04-05     

同じorder上の同じclientidに対して、反対のdate値を持つtypeからすべての行を取得する必要があります。 typeには、BまたはSの2つの値のいずれかしか指定できないことに注意してください。上記の例では、これはrows 23および24

もう1つの制約は、processedの対応する行がtrueに対してorderidでなければならないことです。

これまでのクエリ

SELECT c1.clientid,
       c1.date,
       c1.type,
       c1.itemid,
       c1.amount,
       c2.date,
       c2.type,
       c2.itemid,
       c2.amount

FROM   order c1
INNER JOIN order c2 ON c1.itemid    =  c2.itemid AND
                       c1.date      =  c2.date   AND
                       c1.clientid  =  c2.clientid AND
                       c1.type     <>  c2.type AND
                       c1.id        <  c2.id

INNER JOIN processed p1 ON p1.orderid   =  c1.id AND
                         p1.processed =  true
INNER JOIN processed p2 ON p2.orderid   =  c2.id AND
                         p2.processed =  true

質問:processed = trueは、結合句の一部として、クエリの速度を低下させています。 WHERE句に移動すると、パフォーマンスが大幅に向上します。これは私の興味をそそりました私は理由を知りたい.

主キーとそれぞれの外部キー列にはインデックスが付けられますが、値列(valueprocessedなど)は付けられません。

免責事項:このDB構造を継承しましたが、パフォーマンスの差は約6秒です。

28
Insectatorious

違いが見られる理由は、プランナーがまとめている実行計画によるもので、これは明らかにクエリによって異なります(おそらく、2つのクエリが同じになるように最適化する必要があり、これはバグかもしれません) )。これは、計画者が各ステートメントの結果に到達するために特定の方法で作業する必要があると考えることを意味します。

JOIN内でそれを行う場合、プランナーはおそらくテーブルから選択し、「True」部分でフィルタリングし、結果セットを結合する必要があります。これは大きなテーブルであり、したがって多くのデータを調べる必要があるため、インデックスを効率的に使用することはできません。

WHERE句でそれを行う場合、プランナーはより効率的なルート(つまり、インデックスベースのデータセットまたは事前にフィルタリングされたデータセット)を選択していると思われます。

おそらく、2つの列にインデックスを追加することにより、結合を高速に(高速ではない場合)動作させることができます(Postgresで含まれている列と複数の列インデックスがまだサポートされているかどうかはわかりません)。

要するに、プランナーは結果セットに到達するために2つの異なるルートを選択する問題であり、それらの1つは他のルートほど効率的ではありません。完全なテーブル情報とEXPLAIN ANALYZE情報がなければ、その理由を知ることは不可能です。

特定のクエリがこれを行っている理由の詳細が必要な場合は、詳細情報を提供する必要があります。ただし、その理由は、プランナーが異なるルートを選択しているためです。

追加資料:

http://www.postgresql.org/docs/current/static/explicit-joins.html

スキムしただけで、postgresプランナーは最適化のために結合の順序を変更しないようです。ステートメントの結合の順序を変更して、同じパフォーマンスが得られるかどうかを確認してみてください。

9
Martin