最近、PostgresからSolrに切り替えたところ、クエリの速度が約50倍に向上しました。実行するクエリには複数の範囲が含まれ、データは車両リストです。例:「走行距離<50,000、$ 5,000 <価格<$ 10,000、make = Mazda ...のすべての車両を検索します。」
Postgresの関連するすべての列にインデックスを作成したので、かなり公平な比較になるはずです。 Postgresのクエリプランを見ると、まだ単一のインデックスを使用してからスキャンしているだけです(異なるインデックスをすべて使用できないためだと思います)。
私が理解しているように、PostgresとSolrは漠然と類似したデータ構造(Bツリー)を使用しており、どちらもデータをメモリ内にキャッシュします。だから私はそのような大きなパフォーマンスの違いがどこから来るのだろうと思っています。
アーキテクチャのどのような違いがこれを説明しますか?
まず、SolrはBツリーを使用しません。 Lucene(Solrが使用する基礎ライブラリ)インデックスは、読み取り専用 segments で構成されています。 Luceneは、セグメントごとに、辞書にソートされたセグメントに表示される用語のリストで構成される用語辞書を保持しています。この用語辞書での用語の検索は、バイナリ検索を使用して行われるため、単一用語検索のコストはO(log(t))
です(tは用語の数)。それどころか、標準のRDBMSのインデックスを使用すると、O(log(d))
コストがかかります。dはドキュメントの数です。多くのドキュメントが特定のフィールドで同じ値を共有している場合、これは大きな勝利となります。
さらに、LuceneコミッターのUwe Schindlerは、数年前に非常に高性能な 数値範囲クエリ のサポートを追加しました。 数値フィールド のすべての値に対して、Luceneは精度の異なる複数の値を保存します。これにより、Luceneは範囲クエリを非常に効率的に実行できます。ユースケースは数値範囲クエリを多く活用しているように見えるため、Solrが非常に高速である理由を説明できます。 (詳細については、非常に興味深いjavadocsを読み、関連する研究論文へのリンクを提供してください。)
ただし、SolrにはRDBMSが持つすべての制約がないため、これを行うことができるだけです。たとえば、Solrは一度に1つのドキュメントを更新するのが非常に苦手です(バッチ更新を好む)。
PostgreSQLインスタンスやクエリを調整するために何をしたかについて、実際にはあまり語りませんでした。最適化された形式でクエリをチューニングまたは再作成することで、PostgreSQLクエリの速度が50倍になることは珍しくありません。
ちょうど今週、誰かがJavaと複数のクエリを使用して4時間で到達した距離に基づいて約1か月かかるという方法で書いた職場でのレポートがありました。 (それぞれ数億行の5つの異なるテーブルにヒットする必要がありました。)数分でCTEとウィンドウ関数を使用して書き換え、10分未満で実行し、クエリから目的の結果が直接生成されるようにしました。 。これは4400倍の速度です。
おそらくあなたの質問に対する最良の答えは、各製品で検索を実行する方法の技術的な詳細とは何の関係もありません、各製品でイーズと関係がありますあなたの特定のユースケースのための使用の。明らかに、PostgreSQLよりも簡単にSolrで検索できる高速な方法を見つけることができ、それ以上にならないかもしれません。
PostgreSQLで複数の条件のテキスト検索がどのように行われるか、そしていくつかの小さな調整がパフォーマンスの大きな違いを生む方法の短い例を含めています。迅速かつ簡単に保つために、テキスト形式でWar and Peaceをテストデータベースに実行します。各「ドキュメント」は単一のテキスト行です。データを大まかに定義する必要がある場合は、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 ms、ジン:0.194 ms
-- 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倍以上高速です。明らかに、インデックス作成の利点は、このテストで使用されたものよりも大きなドキュメントの方が劇的です。
もちろん、セットアップは一度限りのものです。 tsv
列を維持するトリガーを使用すると、設定を再実行することなく、変更を即座に検索できます。
遅いPostgreSQLクエリで、テーブル構造(インデックスを含む)、問題のあるクエリ、実行中のEXPLAIN ANALYZE
クエリのほとんどの場合、誰かが問題を発見し、それをより速く実行する方法を提案できます。
[〜#〜] update [〜#〜](16年12月9日)
以前のタイミングを取得するために使用したものについては言及しませんでしたが、日付に基づいて、おそらく9.2メジャーリリースでした。この古いスレッドを偶然見つけて、バージョン9.6.1を使用して同じハードウェアで再試行し、介在するパフォーマンスチューニングがこの例に役立つかどうかを確認しました。 1つの引数のみのクエリでは、パフォーマンスが約2%しか向上しませんでしたが、「女性」と「紳士」の両方の行を検索すると、速度が約0.053ミリ秒に倍増しました(つまり、 53マイクロ秒)GIN(逆)インデックスを使用する場合。
Solrは、ストレージではなく、主にデータの検索用に設計されています。これにより、RDMSに必要な機能の多くを破棄できます。そのため、(むしろ lucene )はデータの純粋なインデックス化に集中しています。
間違いなく発見したように、Solrはインデックスからデータを検索および取得する機能を有効にします。自然な質問につながるのは後者の(オプションの)機能です...「Solrをデータベースとして使用できますか?」
答えは「はい」です。以下を参照してください。
私個人の意見では、Solrは、アプリケーションとデータベースにマスター登録されているデータとの間の検索可能なキャッシュと考えられています。そうすれば、両方の長所を最大限に活用できます。
この最大の違いは、Lucene/Solrインデックスは、リレーショナルクエリ(JOIN)をサポートしない単一テーブルデータベースのようなものであることです。インデックスは通常、検索をサポートするためだけに存在し、データの主要なソースではないことに注意してください。したがって、データベースは「第3正規形」になっている可能性がありますが、インデックスは完全に非正規化され、検索に必要なデータのみが含まれます。
別の考えられる理由は、一般にデータベースが内部フラグメンテーションに悩まされているため、巨大なリクエストに対してあまりにも多くのセミランダムI/Oタスクを実行する必要があることです。
つまり、たとえばデータベースのインデックスアーキテクチャを考慮すると、クエリはインデックスにつながり、それがデータにつながります。回復するデータが広く拡散している場合、結果に時間がかかり、データベースで何が起こるかと思われます。
Solr(Lucene)は inverted index を作成します。ここで、データの取得が非常に高速になります。 I 読み取り PostgreSQLにも同様の機能がありますが、それを使用したかどうかはわかりません。
観察したパフォーマンスの違いは、「検索対象」、「ユーザークエリ」