PostgreSQLインスタンスやクエリを調整するために何をしたかについてはあまり語りませんでした。最適化が改善された形式でクエリを調整および/または再記述することで、PostgreSQLクエリが50倍高速化するのは珍しいことではありません。
ちょうど今週、誰かがJavaと複数のクエリを使用して、4時間でどれだけの距離に到達したかに基づいて、完了するまでに約1か月かかるというレポートが作成されました。(それぞれが数億行の5つの異なるテーブルをヒットする必要がありました。)10分未満で実行され、クエリから直接目的の結果が生成されるように、いくつかのCTEとウィンドウ関数を使用して書き直しました。これは4400倍のスピードアップです。
おそらく、あなたの質問に対する最良の答えは、各製品で検索を実行する方法の技術的な詳細とは関係ありませんが、特定のユースケースの使いやすさと関係があります。明らかに、PostgreSQLよりも問題なくSolrで検索するための高速な方法を見つけることができましたが、それ以上のことにはならないかもしれません。
PostgreSQLで複数の基準のテキスト検索がどのように行われるか、およびいくつかの小さな調整がパフォーマンスに大きな違いをもたらす方法の簡単な例を含めます。すばやく簡単に保つために、私はWar andPeaceをテキスト形式でテストデータベースに実行しています。各「ドキュメント」は1行のテキストです。hstore
データを大まかに定義する必要がある場合は、タイプまたはJSON
列を使用して任意のフィールドに同様の手法を使用できます。独自のインデックスを持つ個別の列がある場合、インデックスを使用する利点ははるかに大きくなる傾向があります。
-- Create the table.
-- In reality, I would probably make tsv NOT NULL,
-- but I'm keeping the example simple...
CREATE TABLE war_and_peace
(
lineno serial PRIMARY KEY,
linetext text NOT NULL,
tsv tsvector
);
-- Load from downloaded data into database.
COPY war_and_peace (linetext)
FROM '/home/kgrittn/Downloads/war-and-peace.txt';
-- "Digest" data to lexemes.
UPDATE war_and_peace
SET tsv = to_tsvector('english', linetext);
-- Index the lexemes using GiST.
-- To use GIN just replace "gist" below with "gin".
CREATE INDEX war_and_peace_tsv
ON war_and_peace
USING gist (tsv);
-- Make sure the database has statistics.
VACUUM ANALYZE war_and_peace;
インデックス作成の設定が完了したら、両方のタイプのインデックスを使用した行数とタイミングを使用した検索をいくつか示します。
-- Find lines with "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'gentlemen');
84行、要点:2.006ミリ秒、ジン:0.194ミリ秒
-- Find lines with "ladies".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies');
184行、要点:3.549ミリ秒、ジン:0.328ミリ秒
-- Find lines with "ladies" and "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
WHERE tsv @@ to_tsquery('english', 'ladies & gentlemen');
1行、要点:0.971ミリ秒、ジン:0.104ミリ秒
さて、GINインデックスはGiSTインデックスよりも約10倍高速だったので、なぜ誰もがテキストデータのインデックスにGiSTを使用するのか不思議に思うかもしれません。答えは、GiSTは一般的に保守が速いということです。したがって、テキストデータが非常に揮発性である場合、GiSTインデックスは全体的な負荷で勝つ可能性がありますが、検索時間または主に読み取りのワークロードにのみ関心がある場合はGINインデックスが勝ちます。
インデックスがない場合、上記のクエリはテーブル全体をスキャンして各行で一致するかどうかを確認する必要があるため、17.943ミリ秒から23.397ミリ秒かかります。
「女性」と「紳士」の両方を含む行のGINインデックス検索は、まったく同じデータベースでのテーブルスキャンよりも172倍以上高速です。明らかに、インデックス作成の利点は、このテストで使用されたものよりも大きなドキュメントでより劇的になります。
もちろん、セットアップは1回限りです。列を維持するためのトリガーを使用するtsv
と、設定をやり直すことなく、加えられた変更を即座に検索できます。
遅いPostgreSQLクエリでは、テーブル構造(インデックスを含む)、問題のクエリ、およびクエリの実行からの出力を表示すると、EXPLAIN ANALYZE
ほとんどの場合、誰かが問題を見つけて、より速く実行する方法を提案できます。
更新(2016年12月9日)
以前のタイミングを取得するために使用したものについては触れませんでしたが、日付に基づくと、おそらく9.2メジャーリリースでした。私はこの古いスレッドに出くわし、バージョン9.6.1を使用して同じハードウェアで再試行し、介在するパフォーマンス調整のいずれかがこの例に役立つかどうかを確認しました。1つの引数のみのクエリでは、パフォーマンスが約2%向上しましたが、GIN(転置)インデックスを使用すると、「女性」と「紳士」の両方の行を検索すると、速度が約2倍の0.053ミリ秒(53マイクロ秒)になりました。