2012-05-07 8 views
0

私は200kタプルのようなものでPostgresqlテーブルを持っています。 私は何をしようとすると、いくつかの行をフィルタリングして、フルテキストのマッチングを使用してそれらを注文です:Postgresql - ソートされたセットの全文オーダー

SELECT * FROM descriptions as d 
WHERE d.category_id = ? 
AND d.description != '' 
AND regexp_replace(d.description, '(...)', '') !~* '...' 
AND regexp_replace(d.description, '...', '') !~* '...' 
AND d.id != ? 
ORDER BY ts_rank_cd(to_tsvector('english', name), plainto_tsquery('english', 'my search words')) DESC LIMIT 5 OFFSET 0'; 

説明フィールド上GINインデックスがあります。

このクエリは、4000未満のレコードがある場合にのみ有効です。その5kまたは6kのように多くの場合、クエリは非常に遅くなります。

私はこのクエリのさまざまなバリエーションを試していました。私が気づいたのは、WHERE句かORDER BY句のどちらかを削除してからスピードアップしたときです。 (もちろん無関係な結果が出る)

この組み合わせを高速化するにはどうすればよいですか?最適化の方法やPostgreSQL以外のソリューションを探すべきですか?

追加質問:

私はさらに実験だし、例えばこれは私が実行が遅すぎると思う最も簡単なクエリです。私は説明から、要点インデックスを使用しているときと、そうでないときを分析することはできますか?

SELECT d.*, d.description <-> 'banana' as dist FROM descriptions as d ORDER BY dist DESC LIMIT 5 

"Limit (cost=16046.88..16046.89 rows=5 width=2425) (actual time=998.811..998.813 rows=5 loops=1)" 
" -> Sort (cost=16046.88..16561.90 rows=206010 width=2425) (actual time=998.810..998.810 rows=5 loops=1)" 
"  Sort Key: (((description)::text <-> 'banana'::text))" 
"  Sort Method: top-N heapsort Memory: 27kB" 
"  -> Seq Scan on products d (cost=0.00..12625.12 rows=206010 width=2425) (actual time=0.033..901.260 rows=206010 loops=1)" 
"Total runtime: 998.866 ms"` 

回答(kgrittnは):DESCキーワードは、KNN-GiSTのために正しいものではなく、それが実際にここに望んでいたではないです。それを削除すると、問題が修正され、正しい結果が得られます。

+0

インデックスはありますか?クエリプランナーはあなたに何を伝えますか? –

+0

私はジーンと要点の指標を試していますが、使用されていないかのように見えます。どのようにプランナーが私に言うかを確認するには?あなたが意味することを説明しますか? – Lubiluk

答えて

0

クエリのexplain analyzeの出力が役立ちます。しかし、私はこのregexp_replace行があなたの問題だと思います。 Postgresのプランナーは、この2行に一致する行の数を知ることができないため、この欠陥のあるクエースに基づいてクエリを推測し、計画しています。

私はこのような関数を作成することをお勧めしたい:

create function good_description(text) returns boolean as $$ 
    select 
    regexp_replace($1, '(...)', '') !~* '...' 
    and 
    regexp_replace($1, '...', '') !~* '...' 
$$ language sql immutable strict; 

そして、この機能を使用してpartialインデックスon expression作成:

create index descriptions_good_description_idx 
    on good_description(description) 
    where description != ''; 

をそしてPostgresが使用することを可能にする方法で問い合わせますこのインデックス:

SELECT * FROM descriptions as d 
WHERE d.category_id = ? 
AND d.description != '' 
AND good_description(d.description) 
AND d.id != ? 
ORDER BY ts_rank_cd(
    to_tsvector('english', name), 
    plainto_tsquery('english', 'my search words') 
) DESC 
LIMIT 5 OFFSET 0; 
+0

あなたがここにいるように見える。実際にEXPLAIN ANALYZEは、カテゴリ内の記述の数に応じて異なる出力を与えます。私は式がパラメータ化され、異なるバージョンが使用されるので、私の正規表現のインデックスを作成することは不可能だと思う。私はregexpフィルタのキャッシュ結果を保持するためだけに別のテーブルを作成し、 – Lubiluk

+0

where節の正規表現フィルタの問題は、実行する前にどれくらい一致するかを大まかに予測することが全く不可能であるということです。これらの正規表現の数が限られている場合、たとえば、regexpが一致するかどうかを示すブール型列をこの表に追加できます。これらの列は、トリガーを使用して簡単に維持できます。また、索引は必要ありません。データベースによって自動的に管理される列統計は、値によってフィルタリングすると、プランナが一致する行の数を正しく推定できる必要があります。これはインデックスよりも速くすべきです。 – Tometzky

0

このタイプのアプリケーションでは、tsearch機能からtrigram機能に移行しました。ベストマッチの数が少ない場合は、はるかに高速です。とにかく、テキスト検索ランキングよりもトライグラムの類似性マッチングの意味を好む人が多いです。

http://www.postgresql.org/docs/current/interactive/pgtrgm.html

「借入」編集した質問から、後でクエリが答えは、コメントのいかだせずに自己完結型にするために、それをフォーマットし、インデックス作成ステートメントを含む:

CREATE INDEX descriptions_description_trgm 
    ON descriptions 
    USING gist (description gist_trgm_ops); 

SELECT d.*, d.description <-> 'banana' as dist 
    FROM descriptions as d 
    ORDER BY dist LIMIT 5; 

このLIMITに当たるまで "距離"シーケンスのGiSTインデックスから行を返します。

+0

はい、そうです。ありがとうございました。 – Lubiluk

+0

私はこのコメントのストリームに基づいて答えを更新し、以前のコメントを削除しています。 (@ルビク、そうしたいかもしれない。) – kgrittn

関連する問題