TodayMySQL データベース 列では、MySQL インデックスと ElasticSearch インデックスの比較を紹介します。
この期間中、製品の検索機能をメンテナンスしていますが、# が表示されるたびに、 # 管理コンソール上で #elasticsearch 彼がどのようにしてこのような効率的なクエリ効率を達成しているのか非常に興味があります。
MySQL を使用して主キーでクエリを実行するよりもさらに高速です。
に基づく全文検索エンジンです。データをセグメント化します。
MySQL と比較すると、大量のインデックス データの管理が得意ですが、データや関連するクエリを頻繁に更新するのは苦手です。
MySQL から始めましょう。インデックスという言葉は誰もがよく知っているはずです。インデックスは通常、一部のクエリ シナリオに存在し、典型的な時間の空間です。交換の場合もございます。
以下内容以 Innodb 引擎为例。复制代码
MySQL のインデックスを自分で設計すると仮定すると、どのようなオプションがありますか?
Java に対応します。
HashMap
O (1) 、たとえば、
id=3 のデータをクエリしたい場合、3 をハッシュし、この配列内の対応する位置を見つける必要があります。
1≤id≤6 のような間隔データをクエリしたい場合、ハッシュ テーブルはそれを十分に満たすことができません。順序付けされていないため、すべてのデータは次のとおりである必要があります。どのデータがこの間隔に属しているかを知ることができます。
id=4 # をクエリする場合には非常に高くなります。 ## データの場合、二分検索を使用するだけでデータ O(logn)
を効率的に見つけることができます。 同時に、データも順序付けされているため、当然間隔クエリをサポートできます。そのため、順序付けされた配列はインデックスとしての使用に適しているように見えますか?
もちろんそうではありません。もう 1 つの大きな問題:
id=2.5 でデータを挿入すると、後続のデータをすべて同時に 1 ビット移動する必要があり、書き込み効率が非常に低くなります。 Balanced Binary Tree
したがって、id=11
のデータをクエリしたいと仮定すると、最終的には 10—>12—>11
をクエリするだけで済みます。時間計算量は O(logn)
であり、データを書き込む場合も同様に O(logn)
です。 しかし、まだ間隔範囲検索は十分にサポートされていません。
のデータをクエリしたいとすると、最初に 10 個のノードの左側のサブツリーをクエリする必要があります。次に、10 ノードの左側のサブツリーをクエリします。最終的にすべてのデータをクエリできるのは、右側のサブツリーだけです。 結果として、そのようなクエリ効率は高くありません。
ジャンプ テーブル
の sort set
はスキップ テーブルを使用して実装されます。 <p>ここでは、ジャンプ テーブルによって実現されるデータ構造の利点を簡単に紹介します。 </p>
<p>誰もが知っているように、<strong>順序付きリンク リスト</strong> をクエリすることすら効率的ではありません。二分探索に配列添字を使用できないため、時間計算量は <code>o( n)
になります。
しかし、以下に示すように、リンク リストを巧みに最適化して、二分検索を偽装して実装することもできます。
# プライマリを抽出できます。最下位データのインデックスとセカンダリ インデックス データ量に応じて、N レベルのインデックスを抽出できます。
クエリを実行するとき、ここのインデックスを使用して、二分検索を偽装して実装できます。
id=13
のデータをクエリしたいとします。必要なのは 4 つのノード 1->7->10->13## だけです。 # to query データの場合、数が大きいほど効率の向上がより顕著になります。
リンクリストはターゲットノードへの順序です) データの全範囲がクエリされます。
同時に、インデックスには実際のデータを格納せず、ポインターのみを格納するため、データが格納される下部のリンク リストと比較して、占有されるスペースは無視できます。 バランス型バイナリツリーの最適化しかし実際には、MySQL の
Innodb はスキップ テーブルを使用せず、
と呼ばれるテーブルを使用します。 B ツリー データ構造。
B ツリーは、バランスの取れた二分木から進化したものと考えることができます。
はインデックス ファイルをディスクに直接保存します。
これは、後述する elasticsearch インデックスとは少し異なります。
#インデックスはディスクに保存されるため、ディスクの IO をできる限り削減する必要があります (ディスク IO の効率はメモリの効率とは桁違いです)上の図からわかるように、データのクエリには少なくとも 4 回の IO 時間が必要です。明らかに、IO 回の回数はツリーの高さと密接に関係しています。ツリーの高さが低いほど、 、IO 回数が少ないほどパフォーマンスが向上します。木の高さを低くするにはどうすればよいでしょうか?
#二分木を三項木に変更してみると、木の高さが大幅に下がり、数値が下がります。データクエリ時の IO は自然に減少し、クエリ効率が大幅に向上します。
実はこれが B ツリーの起源です。 実際、上の図のB ツリー
を理解することで、日々の作業の細部を最適化することもできます。 ; たとえば、なぜ最も必要なのか 良いものは順番に増えていくのでしょうか?書き込む主キー データが順序付けされていないと仮定すると、後で書き込まれるデータの ID が前に書き込まれたデータの ID よりも小さくなる可能性があります。これは、
B ツリー# を維持するときに必要になる可能性があります。 ## インデックス。モバイルはすでにデータを書き込んでいます。
そのため、データベースの主キーは可能な限り増加傾向にする必要があり、最も合理的なのは、分割テーブルの状況を考慮せずに主キーを自動インクリメントすることです。
全体として、アイデアはスキップ テーブルのアイデアに似ていますが、使用シナリオに基づいて調整が行われています (たとえば、すべてのデータはリーフ ノードに格納されます)。 ES インデックス
チャットの後、Elasticsearch
がインデックスをどのように使用するかを見てみましょう。
前方インデックス
と呼ばれるデータ構造が使用されます。転置インデックスについて正式に話す前に、彼の反対のがランク付けされることについて話しましょう。索引 ###。
上の図は例です。doc_id
を通じて特定のオブジェクトをクエリする方法は、Forward Index## を使用して呼び出されます。 # は、実際にはハッシュ テーブルとしても理解できます。
本質は、キーを通じて価値を見つけることです。たとえば、
doc_id=4 を通じて、データ
name=jetty wang,age=20 をすばやくクエリできます。
name に
li が含まれるデータをクエリしたい場合は?このように効率的にクエリを実行するにはどうすればよいでしょうか?
li が含まれているかどうかを判断することしかできません。これは非常に非効率です。
name には
li# が含まれます。 ## データの場合は、このインデックス構造を通じて Posting List
に含まれるデータをクエリし、マッピングを通じて最終データをクエリするだけで済みます。 このインデックス構造は実際には
です。 用語辞書
を効率的にクエリするにはどうすればよいでしょうか? Term
を追加する限り、これまでの経験と組み合わせることができます。順番に、バイナリ ツリー検索ツリーのデータ構造を使用して、o(logn)
の下のデータをクエリできます。 テキストを独立した
に分割するプロセスは、実際には単語の分割とよく呼ばれるものです。 すべての
を結合したものが Term Dictionary
であり、単語辞書とも呼ばれます。
が大量に存在することになります。このような転置インデックス データ構造がメモリに保存されていれば、間違いなくしかし、MySQL
のようにディスクに保存されている場合、効率はそれほど高くありません。 用語インデックス
全体をメモリに入れることはできないため、用語辞書
インデックスを作成してメモリに置きます。 このようにして、
を効率的にクエリでき、最終的に投稿リスト
を用語辞書
を通じてクエリできるようになります。 MySQL
の
と比較すると、ディスク IO
も数倍削減されます。
を使用できます。これはよく言われることです辞書ツリー
を保存します。 辞書ツリーの詳細については、ここを参照してください。
を検索する場合、最初のステップは # を検索することです。メモリ内の ##Term Index は、
Term Dictionary 辞書ファイル内の
j で始まる
Term の位置をクエリします (この位置はファイル ポインタである場合があります) 、おそらく間隔範囲)。
次に、この位置範囲内のすべての
Term を取り出します。これらはソートされているため、二分検索によって特定の位置をすばやく見つけることができます。このようにして、## をクエリできます。 #投稿リスト
。
最後に、投稿リスト
の位置情報を介して、元のファイルから目的のデータを取得できます。 さらなる最適化
もちろん、ElasticSearch
では、多くの対象を絞った最適化も行っています。2 つのフィールドを取得する場合、
たとえば、name=li と age=18
のデータをクエリする必要があります。このとき、それぞれの結果 投稿リスト
を取得する必要があります。この2つのフィールドを通じて。
以上がMySQL インデックス VS ElasticSearch インデックスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。