38

私はテーブルを持っていると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として

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値を持つようにする必要があります。type2つの値のうちの1つのみを持つことができることに注意してください-BまたはS。上記の例では、これは行2324です。

もう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句に移動すると、パフォーマンスが大幅に向上します。これは私の興味をそそりました、そして私は理由を知りたいです。

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

免責事項:私はこのDB構造を継承しており、パフォーマンスの違いは約6秒です。

4

1 に答える 1

19

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

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

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

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

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

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

追加の読み物:

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

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

于 2012-06-01T12:25:24.643 に答える