68

最近、PostgresからSolrに切り替えたところ、クエリが最大50倍高速化されました。実行するクエリには複数の範囲が含まれ、データは車両リストです。例:「走行距離<50,000、$ 5,000<価格<$10,000、make=Mazda...のすべての車両を検索します。」

Postgresの関連するすべての列にインデックスを作成したので、かなり公平な比較になるはずです。Postgresでクエリプランを見ると、それはまだ単一のインデックスを使用してからスキャンしていました(すべての異なるインデックスを利用できなかったためだと思います)。

私が理解しているように、PostgresとSolrは漠然と類似したデータ構造(Bツリー)を使用しており、どちらもデータをメモリにキャッシュします。ですから、このような大きなパフォーマンスの違いはどこから来るのだろうと思います。

アーキテクチャのどのような違いがこれを説明しますか?

4

5 に答える 5

138

まず、SolrはBツリーを使用しません。Lucene(Solrが使用する基礎となるライブラリ)インデックスは、読み取り専用セグメントで構成されています。Luceneは、セグメントごとに、辞書式順序でセグメントに表示される用語のリストで構成される用語辞書を保持しています。この用語辞書で用語を検索するのは二分探索を使用するため、単一用語検索のコストは次のようになりますO(log(t))。ここで、tは用語の数です。逆に、標準のRDBMSコストのインデックスを使用すると、O(log(d))dはドキュメントの数になります。多くのドキュメントが特定のフィールドで同じ値を共有している場合、これは大きなメリットになります。

さらに、LuceneコミッターのUwe Schindlerは、数年前に非常にパフォーマンスの高い数値範囲クエリのサポートを追加しました。数値フィールドのすべての値について、Luceneは異なる精度でいくつかの値を格納します。これにより、Luceneは範囲クエリを非常に効率的に実行できます。あなたのユースケースは数値範囲クエリを多く活用しているように見えるので、これがSolrが非常に高速である理由を説明している可能性があります。(詳細については、非常に興味深いjavadocsを読み、関連する研究論文へのリンクを提供してください。)

ただし、Solrがこれを実行できるのは、RDBMSが持つすべての制約がないためです。たとえば、Solrは一度に1つのドキュメントを更新するのが非常に苦手です(バッチ更新を優先します)。

于 2012-04-07T11:31:43.813 に答える
41

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マイクロ秒)になりました。

于 2012-04-07T14:55:47.990 に答える
7

Solrは、ストレージではなく、主にデータの検索用に設計されています。これにより、RDMSに必要な機能の多くを破棄できます。そのため、それ(またはむしろlucene)は純粋にデータのインデックス作成に集中します。

ご存じのとおり、Solrを使用すると、インデックスからデータを検索および取得することができます。後者の(オプションの)機能が自然な質問につながります...「Solrをデータベースとして使用できますか?」

答えは「はい」と認定されており、次のことを紹介します。

私の個人的な意見では、Solrは、私のアプリケーションとデータベースにマスターされているデータとの間の検索可能なキャッシュとして最もよく考えられています。そうすれば、私は両方の世界を最大限に活用できます。

于 2012-04-07T09:30:25.027 に答える
6

この最大の違いは、Lucene / Solrインデックスは、リレーショナルクエリ(JOIN)をサポートしない単一テーブルデータベースのようなものであるということです。インデックスは通常、検索をサポートするためだけにあり、データの主要なソースではないことに注意してください。したがって、データベースは「第3正規形」である可能性がありますが、インデックスは完全に非正規化され、検索に必要なデータのみが含まれます。

もう1つの考えられる理由は、一般にデータベースが内部の断片化に悩まされていることです。データベースは、巨大な要求に対してあまりにも多くのセミランダムI/Oタスクを実行する必要があります。

つまり、たとえば、データベースのインデックスアーキテクチャを考慮すると、クエリはインデックスにつながり、インデックスはデータにつながります。回復するデータが広く普及していると、結果に時間がかかり、データベースで起こっているように見えます。

于 2012-04-07T10:19:33.070 に答える
1

これこれを読んでください。

Solr(Lucene)は、データの取得が非常に高速になる転置インデックスを作成します。PostgreSQLにも同様の機能があること を読みましたが、それを使用したかどうかはわかりません。

観察されたパフォーマンスの違いは、「何が検索されているのか」、「ユーザーのクエリは何ですか?」にも説明できます。

于 2012-04-07T08:52:29.947 に答える