23

次の保管と検索の問題にどのように取り組みますか?

約 2.000.000 行が毎日 (365 日/年) 追加され、行ごとに次の情報が追加されます。

  • id (一意の行識別子)
  • entity_id (1 から 2.000.000 までの値を取る)
  • date_id (毎日 1 ずつ増加 - 1 ~ 3.650 (10 年: 1*365*10) の値を取る)
  • value_1 (1 から 1.000.000 までの値を取る)
  • value_2 (1 から 1.000.000 までの値を取る)

entity_id と date_id の組み合わせは一意です。したがって、エンティティと日付ごとに最大で 1 行をテーブルに追加できます。データベースは、10 年分の毎日のデータ (7.300.000.000 行 (3.650*2.000.000)) を保持できる必要があります。

以上が書き込みパターンである。読み取りパターンは単純です。すべてのクエリは特定の entity_id に対して行われます。つまり、entity_id = 12345 を記述しているすべての行を取得します。

トランザクション サポートは必要ありませんが、ストレージ ソリューションはオープンソースである必要があります。理想的には MySQL を使用したいのですが、提案は受け付けています。

さて、説明されている問題にどのように取り組みますか?

更新:読み取りと書き込みのパターンについて詳しく説明するように求められました。テーブルへの書き込みは 1 日 1 回のバッチで行われ、新しい 2M エントリが一度に追加されます。読み取りは、1 秒ごとに 1 回の読み取りで継続的に行われます。

4

7 に答える 7

28

「さて、説明された問題にどのように取り組みますか?」

シンプルなフラットファイル付き。

これが理由です

「すべてのクエリは特定の entity_id に対して行われます。つまり、entity_id = 12345 を記述しているすべての行を取得します。」

2.000.000 エンティティがあります。エンティティ番号に基づくパーティション:

level1= entity/10000
level2= (entity/100)%100
level3= entity%100

データの各ファイルはlevel1/level2/level3/batch_of_data

次に、ディレクトリの特定の部分にあるすべてのファイルを読み取って、処理用のサンプルを返すことができます。

リレーショナル データベースが必要な場合は、特定の entity_id のファイルをデータベースにロードして使用します。


日付番号を編集 します。

  1. date_id/entity_id一意性ルールは、処理する必要があるものではありません。これは、(a) ファイル名に自明に課され、(b) クエリには関係ありません。

  2. date_idロールオーバー」は何の意味もありません。クエリがないため、名前を変更する必要はありません。はdate_id、エポック日付から際限なく単純に成長するはずです。古いデータを消去する場合は、古いファイルを削除してください。

に依存するクエリはないためdate_id、何もする必要はありません。重要なすべてのファイル名にすることができます。

を結果セットに含めるにはdate_id、ファイルの各行にある他の 4 つの属性とともにファイルに書き込みます。


開閉時に編集

書き込むには、ファイルを開いたままにしておく必要があります。定期的なフラッシュ (またはクローズ/再オープン) を行って、データが実際にディスクに移動することを保証します。

ライターのアーキテクチャには 2 つの選択肢があります。

  1. さまざまなソースからのデータを統合する単一の「ライター」プロセスを用意します。これは、クエリが比較的頻繁に発生する場合に役立ちます。書き込み時にデータをマージする料金が発生します。

  2. 複数のファイルを同時に開いて書き込みます。クエリを実行するとき、これらのファイルを 1 つの結果にマージします。これは、クエリが比較的まれな場合に役立ちます。クエリ時にデータをマージする料金が発生します。

于 2009-03-20T10:44:49.787 に答える
13

パーティショニングを使用します。読み取りパターンでは、entity_idハッシュでパーティション分割する必要があります。

于 2009-03-20T10:36:56.187 に答える
5

次の質問を参照してください。

大きな主キー: 10 億以上の行 MySQL + InnoDB?

大きな MySQL テーブル

個人的には、行幅を計算して、テーブルの大きさを把握することも考えています (最初のリンクのパーティショニング ノートに従って)。

S

于 2009-03-20T10:36:42.537 に答える
4

あなたのアプリケーションは私のものと同じ特徴を持っているようです。この問題を効率的に解決するために、MySQL カスタム ストレージ エンジンを作成しました。ここに記載されています

データが、20 バイト (1 日あたり 1 つのエンティティの行) の 3650 行 (1 日あたり 1 行) を含む 2M の固定長エントリ (エンティティごとに 1 つ) の配列としてディスク上に配置されていると想像してください。

読み取りパターンは 1 つのエンティティを読み取ります。ディスク上で連続しているため、シークが 1 回 (約 8 ミリ秒) かかり、3650x20 = 約 80K がおそらく 100MB/秒で読み取られます。パターン。

更新では、ディスク上の 2M の異なる場所に 20 バイトを書き込む必要があります。最も単純なケースでは、それぞれ約 8 ミリ秒かかる 2M のシークが必要になるため、2M*8ms = 4.5 時間かかります。データを 4 つの「raid0」ディスクに分散すると、1.125 時間かかることがあります。

ただし、これらの場所は 80K しか離れていません。つまり、16MB ブロック (通常のディスク キャッシュ サイズ) 内にそのような場所が 200 あるため、最大 200 倍高速に動作できます。(1 分) 現実は 2 つの間のどこかにあります。

私のストレージ エンジンは、固定長配列よりも少し汎用性がありますが、そのような哲学に基づいて動作します。

私が説明したことを正確にコーディングできます。コードを MySQL プラガブル ストレージ エンジンに入れるということは、MySQL を使用して、さまざまなレポート ジェネレーターなどでデータをクエリできることを意味します。

ちなみに、保存された行から日付とエンティティ ID を削除することができ (これらは配列インデックスであるため)、一意の ID である可能性があります。 2 つの値を 3 バイトの int として格納します。保存された行は 6 バイトで、16M あたり 700 回の更新があるため、挿入が高速になり、ファイルが小さくなります。

フラットファイルと比較して編集

コメントは一般的にフラットファイルを支持していることに気付きました。ディレクトリはファイル システムによって実装された単なるインデックスであり、通常は比較的少数の比較的大きなアイテム用に最適化されていることを忘れないでください。ファイルへのアクセスは一般に最適化されているため、比較的少数のファイルが開かれていることが想定され、開いているファイルと閉じているファイル、および開いている各ファイルのオーバーヘッドが比較的高くなります。これらの「相対的」はすべて、データベースの通常の使用に関連しています。

ファイル システム名をエンティティ ID のインデックスとして使用することは、1 から 2Million までの非スパース整数であると考えていますが、直感に反しています。たとえば、プログラミングでは、ハッシュテーブルではなく配列を使用します。また、単に配列の実際の操作である可能性のある高価なアクセスパスに対して、必然的に大量のオーバーヘッドが発生します。

したがって、フラット ファイルを使用する場合は、フラット ファイルを1 つだけ使用してインデックスを作成してみませんか?

パフォーマンスの編集

このアプリケーションのパフォーマンスは、ディスクのシーク時間に支配されます。上で行った計算により、実行できる最善の方法が決まりました (ただし、SELECT を遅くすることで INSERT を速くすることはできますが、両方を改善することはできません)。データベース、フラット ファイル、または 1 つのフラット ファイルのいずれを使用するかは問題ではありませんが、実際には必要のないシークを追加して、さらに速度を低下させることができますたとえば、インデックス作成 (ファイル システム インデックスかデータベース インデックスかに関係なく) は、「配列ルックアップ」と比較して余分な I/O を引き起こし、速度が低下します。

ベンチマーク測定の編集

あなたのテーブルに非常によく似た (またはあなたのパーティションの 1 つとほぼ同じ) テーブルがあります。2M (あなたの 32 分の 1) ではなく、64K のエンティティと 2788 の「日」でした。テーブルは、同じ INSERT 順序で作成され、同じインデックス (entity_id,day) を持ちます。1 つのエンティティに対する SELECT は、2788 日を検査するのに 20.3 秒かかります。これは、予想どおり、1 秒あたり約 130 シークです (平均シーク時間 8 ミリ秒のディスク上)。SELECT 時間は日数に比例し、エンティティの数にはあまり依存しません。(シーク時間が速いディスクでは高速になります。RAID0 で SATA2 のペアを使用していますが、大きな違いはありません)。

テーブルをエンティティの順序に並べ替える場合 ALTER TABLE x ORDER BY (ENTITY,DAY) 次に、同じ SELECT に 198 ミリ秒かかります (1 回のディスク アクセスで順序エンティティを読み取るため)。ただし、ALTER TABLE 操作が完了するまでに 13.98 日かかりました (182M 行の場合)。

測定値からわかることは他にもいくつかあります。 1. インデックス ファイルは、データ ファイルと同じ大きさになります。このサンプル テーブルでは 3GB です。つまり、(私のシステムでは)メモリ速度ではなくディスク速度でのすべてのインデックスです。

2.INSERT率は対数的に低下します。データ ファイルへの INSERT は線形ですが、インデックスへのキーの挿入はログです。1 億 8000 万レコードで、1 秒あたり 153 回の INSERT を取得していました。これは、シーク レートにも非常に近い値です。これは、MySQL がほぼすべての INSERT に対してリーフ インデックス ブロックを更新していることを示しています (エンティティにインデックスが付けられているが、日付順に挿入されているため、予想どおりです)。したがって、毎日 2M 行を挿入するのに 2M/153 秒 = 3.6 時間かかることになります。(システムまたはディスク全体のパーティションによって得られる効果で除算されます)。

于 2009-03-21T03:51:33.143 に答える
2

私は同様の問題を抱えていました(ただし、はるかに大きな規模で-毎日の年間使用量について)

1 つの大きなテーブルを使用すると、停止してしまいました。数か月間引き抜くことはできますが、最終的には分割することになると思います。

テーブルにインデックスを作成することを忘れないでください。そうしないと、クエリごとに小さなデータをいじることになります。ああ、大量のクエリを実行したい場合は、フラット ファイルを使用してください

于 2009-03-20T10:46:29.143 に答える
1

読み取りパターンの説明は十分ではありません。取得するデータの量、クエリで発生する偏差の頻度と程度を記述する必要があります。

これにより、一部の列で圧縮を行うことを検討できます。

アーカイブとパーティション化も検討してください。

于 2009-03-20T10:43:17.497 に答える
0

数百万行の巨大なデータを処理したい場合は、時間を記録してデータをデータベースに保存する時系列データベースに似ていると考えることができます。データを保存する方法のいくつかは、InfluxDB と MongoDB を使用することです。

于 2014-10-24T04:07:42.883 に答える