0

私は 200k タプルのような 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 以外のソリューションを探す必要がありますか?

追加の質問:

私はさらに実験しています。たとえば、これは実行が遅すぎると思われる最も単純なクエリです。Gist インデックスを使用する場合と使用しない場合は、Explain Analyst からわかりますか?

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 では正しくなく、実際にはここでは必要ありません。削除すると問題が修正され、正しい結果が得られます。

4

2 に答える 2

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;

これにより、GiSTインデックスから、に到達するまで「距離」シーケンスで行LIMIT返されます。

于 2012-05-07T16:45:08.347 に答える
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;

そして、この関数を使用して式の部分インデックスを作成します:

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;
于 2012-05-07T22:01:45.893 に答える