2013-11-04 10 views
7

私が持っている次の表のサイズでこののPostgreSQL:ひどく遅いORDERキーの順序として、主キーを持つBY

enter image description here

ようなモデル:今すぐ

+------------------+-------------+ 
| Table   | Records | 
+------------------+-------------+ 
| JOB    |   8k | 
| DOCUMENT   |  150k | 
| TRANSLATION_UNIT |  14,5m | 
| TRANSLATION  |  18,3m | 
+------------------+-------------+ 

次のクエリ

select translation.id 
from "TRANSLATION" translation 
    inner join "TRANSLATION_UNIT" unit 
    on translation.fk_id_translation_unit = unit.id 
    inner join "DOCUMENT" document 
    on unit.fk_id_document = document.id  
where document.fk_id_job = 11698 
order by translation.id asc 
limit 50 offset 0 

90セコndsを終了してください。 ORDER BYLIMIT句を削除すると、19.5秒となります。 ANALYZEは、クエリを実行する直前にすべてのテーブルで実行されていました。クエリプラン

+------------------+-------------+ 
| Table   |  Records | 
+------------------+-------------+ 
| JOB    |   1 | 
| DOCUMENT   |  1200 | 
| TRANSLATION_UNIT | 210,000 | 
| TRANSLATION  | 210,000 | 
+------------------+-------------+ 

:この特定のクエリでは、これらの基準を満たすレコードの数であり、

enter image description here

修正のためのクエリプランORDER BYなしLIMIThereです。

データベースパラメータ:

PostgreSQL 9.2 

shared_buffers = 2048MB 
effective_cache_size = 4096MB 
work_mem = 32MB 

Total memory: 32GB 
CPU: Intel Xeon X3470 @ 2.93 GHz, 8MB cache 

誰もがこのクエリと間違っているものを見ることができますか?

UPDATE: BY ORDERない同じクエリに対してQuery plan(まだLIMIT句を使用して)。

+0

Postgreのためのオプティマイザのしくみを教えてください。たとえば、あなたの選択から選択して、オプティマイザなしでこれを注文することができますか? – Paul

+0

ちょうど幸運な推測。あなたはjoinのwhere節を動かすことができますか?この場合、 'where'を'と 'で置き換えてください。 – foibs

+0

@foibs:これは何の違いもありません。 Postgresのオプティマイザは、両方のバージョンが同じであることを検出するほどスマートです。 –

答えて

1

翻訳時にコンポジットインデックス(fk_id_translation_unit、id)が設定されていますか?それは、テーブルを介してtranslation.idにアクセスする必要性を避けることによって助けになると思います。

+0

'fk_id_translation_unit'と' id'カラムを組み合わせた複合インデックスを意味していますか?私はしませんが、試してみるかもしれません。 – twoflower

+0

私が見る利点は、必要なデータを取得するために変換テーブル自体に全くアクセスする必要がないことです。 –

+0

結果セットに 'TRANSLATION.id'が必要なので、そうです。 PostgreSQLのパフォーマンスフォーラムに参加している人は、データベースを非正規化して 'fk_id_job'を' TRANSLATION'に直接追加することを勧めました。 – twoflower

2

これはコメントには長すぎます。 order by句を削除すると、リンゴとオレンジを比較しています。 order byがなければ、クエリの処理部分は50行しか必要としません。

order byでは、ソートされる前にすべての行を生成する必要があり、上位のいくつかを選択する必要があります。 order byおよびlimit句を削除した場合、クエリにかかる時間はどのくらいですか?

translation.idが主キーであるという事実は、処理にいくつかの結合(結果をフィルタリングする)が必要なため、違いはありません。

EDIT:

私はこれが最初の結果をソートして取得するためにテーブルを作成し、別のためにCTEでどのように動作するかを疑問に思う:

with CTE as (
    select translation.id 
    from "TRANSLATION" translation 
      inner join "TRANSLATION_UNIT" unit 
      on translation.fk_id_translation_unit = unit.id 
      inner join "DOCUMENT" document 
      on unit.fk_id_document = document.id  
    where document.fk_id_job = 11698 
    ) 
select * 
from CTE 
order by translation.id asc 
limit 50 offset 0; 
+0

あなたはゴードンですが、その2つの質問は比類のないものです。私は 'ORDER BY'と' LIMIT'の両方を使わずにクエリを実行したところ、19.5秒かかりました。クエリプランは[こちら](http://explain.depesz.com/s/Qs0) – twoflower

+0

@ twoflowerです。 。 。あなたは大量のデータを持っています。私はPostgresの最適化パラメータにあまり慣れていませんが、メモリを増やすためにバッファサイズを増やすことができれば、パフォーマンスが向上するかもしれません。 –

+1

はい、ボリュームがかなり大きいので、レコードをフェッチするのに19.5秒かかりません。しかし、私が奇妙に感じるのは、このデータセット(cca 212,000レコード)を注文するだけでさらに70秒が追加されるということです。 – twoflower

関連する問題