web-dev-qa-db-ja.com

ソートされた文字列テーブル(SSTable)またはデータベースインデックスのB +ツリー?

この例を示すために2つのデータベースを使用: CouchDB および Cassandra

CouchDB

CouchDBはドキュメントインデックスにB +ツリーを使用します( 巧妙な変更 を使用して追加専用環境で機能します)-より具体的には、ドキュメントが変更(挿入/更新/削除)されると、実行中のデータベースに追加されますファイルおよび完全なリーフ-> Nodeドキュメントの直後の更新されたリビジョンによって影響を受けるすべてのノードのB +ツリーからのパス.

これらの部分測定インデックスリビジョンは、変更の右側にインライン化されます。これにより、完全なインデックスは、ファイルの最後に追加された最新のインデックス変更と、データファイルでさらに関連があり、まだ追加されていない追加のピースの結合になります。まだ変更されていません。

B +ツリー の検索はO(logn)です。

カサンドラ

Cassandraは、レコードキーをメモリ内のテーブルに並べ替えて保持し(この質問では配列と見なします)、それらを別々の(並べ替えられた) sorted-string tables として書き出します。

これらすべてのテーブルのコレクションは、(私が理解している限りでは)「インデックス」と考えることができます。

Cassandraは、時々 これらのソート済み文字列テーブルをコンパクト/結合 する必要があり、インデックスのより完全なファイル表現を作成します。

検索 ソートされた配列 はO(logn)です。

質問

CouchDBでの部分的なB +ツリーチャンクの維持とCassandraでの部分的なソートされた文字列のインデックスのどちらかを維持することの間の同様のレベルの複雑さを仮定し、両方がO(logn)データベースインデックスをより適切に表すには、どの検索時間を使用すると思いますか。その理由は何ですか。

特に魅力的な実装の詳細が他にあるか、または両方がウォッシュであり、操作したい/より理にかなったデータ構造を選択した場合、私は特に興味があります開発者に。

考えてくれてありがとう。

42
Riyad Kalla

BTreeインデックスをSSTableインデックスと比較するときは、書き込みの複雑さを考慮する必要があります。

  • コピーオンライトBTreeにランダムに書き込む場合、ランダムな読み取りが発生します(リーフノードとパスのコピーを行うため)。そのため、書き込みはディスク上でシーケンシャルになりますが、RAMよりも大きいデータセットの場合、これらのランダムな読み取りはすぐにボトルネックになります。 SSTableのようなインデックスの場合、書き込み時にそのような読み取りは行われません-順次書き込みのみになります。

  • また、最悪の場合、BTreeを更新するたびにlog_b N IOが発生する可能性があることも考慮する必要があります。つまり、すべてのキーに対して3つまたは4つのブロックを書き込むことになります。キーサイズがブロックサイズよりはるかに小さい場合、これは非常に高価です。 SSTableのようなインデックスの場合、各書き込みIOには可能な限り多くの新しいキーが含まれるため、IO各キーのコストは1/B..

実際には、これにより、SSTableに似たものがBTreesより数千倍(ランダムな書き込みの場合)速くなります。

実装の詳細を検討したところ、BTableのロック戦略が非常に複雑になったため、SSTableのようなインデックスを(ほとんど)ロックフリーで実装する方がはるかに簡単であることがわかりました。

読み取りコストも再検討する必要があります。 BTreeはランダムポイント読み取りのO(log_b N)ランダムIOよりも正しいですが、SSTableのようなインデックスは実際にはO(#sstables。log_b N)です。適切なマージスキームがない場合、#sstablesはNに比例します。これを回避するためのさまざまなトリックがあります(たとえば、ブルームフィルターを使用)。ただし、これらは小さなランダムな範囲のクエリには役立ちません。これは、Cassandraで見つけたものです。

書き込み負荷が高い場合のCassandra

これが、私たちの(GPL)ストレージエンジンであるCastleがわずかに異なる方法でマージし、書き込みパフォーマンス(O(log ^ 2 N/B))。実際には、書き込みについても、CassandraのSSTableインデックスよりも高速であることがわかります。

これについてもっと知りたいのであれば、私はそれがどのように機能するかについて話をしました:

53
tom.wilkie

Tokutek で使用されるフラクタルツリーは、データベースのより良いインデックスだと思います。これらは、Bツリーよりも実際の20倍から80倍の改善を提供します。

フラクタルツリーインデックスがどのように機能するかについての優れた説明があります here

9
Will

各アプローチについても言及すべきいくつかの事柄:

Bツリー

  • 読み取り/書き込み操作は、対数関数O(logn)と見なされます。ただし、単一のデータベース書き込みにより、ストレージシステムで複数の書き込みが発生する可能性があります。たとえば、ノードがいっぱいになった場合、ノードを分割する必要があります。つまり、2つの新しいノードに2つの書き込みがあり、親ノードを更新するために1つの追加の書き込みがあります。親ノードもいっぱいだった場合、それがどのように増加するかを確認できます。
  • 通常、Bツリーは、各ノードがページのサイズを持つような方法で格納されます。これにより、書き込み増幅と呼ばれる現象が発生し、1バイトを更新する必要がある場合でも、ページ全体が書き込まれます。
  • 書き込みは通常ランダムです(順次ではありません)、このため、特に磁気ディスクの場合は遅くなります

SSTables

  • SSTableは通常、次のアプローチで使用されます。あなたが説明したように、memtableと呼ばれるメモリ内構造があります。時々、この構造はSSTableにディスクにフラッシュされます。その結果、すべての書き込みはmemtableに送られますが、読み取りは現在のmemtableにない可能性があります。その場合、永続化されたSSTablesで検索されます。
  • その結果、書き込みはO(logn)になります。ただし、これらはメモリ内で実行されるため、Bツリーのディスクでの対数演算よりも桁違いに高速であることを常に念頭に置いてください。完全を期すために、書き込みはクラッシュリカバリのために先行書き込みログにも書き込まれることを言及する必要があります。ただし、これらはすべて順次書き込みであるため、Bツリーのランダム書き込みよりもはるかに効率的であると予想されます。
  • メモリから(memtableから)提供される場合、読み取りもはるかに高速であることが期待されます。ただし、古いディスクベースのSSTableを調べる必要がある場合、読み取りはBツリーよりもかなり遅くなる可能性があります。ディスクリードを実行せずにSSTableに値が含まれているかどうかを確認するために、ブルームフィルターの使用など、その周りにいくつかの最適化があります。
  • あなたが述べたように、SSTableをマージするために使用されるcompactionと呼ばれるバックグラウンドプロセスもあります。これにより、削除された値を削除して断片化を防ぐことができますが、書き込み負荷が大きくなり、着信操作の書き込みスループットに影響を与える可能性があります。

明らかになると、これら2つのアプローチの比較ははるかに複雑になります。具体的な比較を提供するための非常に単純化された試みでは、次のように言えるでしょう。

  • SSTableは、Bツリーよりもはるかに優れた書き込みスループットを提供します。ただし、継続的な圧縮により、動作の安定性は低下すると予想されます。この例は このベンチマークの比較 で確認できます。
  • Bツリーは通常、トランザクションセマンティクスが必要なユースケースに適しています。これは、各キーが1か所にしか見つからない(SSTableとは対照的に、いくつかの古い値が複数のSSTableに存在する可能性がある)こと、および値の範囲を木。つまり、キーレベルおよび範囲レベルのロックメカニズムを実行する方が簡単です。

参考文献

[1] LevelDBとMySQLのパフォーマンス比較

[2] データ集約型アプリケーションの設計

4
Dimos

LSMツリーは、構造化されたストレージエンジン上のBツリーよりも優れています。ランダム書き込みをaofに変換します。これがLSM-Tree srcです: https://github.com/shuttler/lsmtree

1
BohuTANG