web-dev-qa-db-ja.com

MySQLに大きな3次元配列を格納するのに最適なアーキテクチャは何ですか?

MySQLで大規模な3次元データベースを作成したいと考えています。構造は基本的に標準のMySQLテーブルであり、時間コンポーネント/ディメンションが追加されています。次の類推を参照してください。

{x、y、z} = {列、行、時間}

Z次元は時間になりますので、なるべく格納したいです。適度なパフォーマンスで、合計約1TBの保存データを期待しています。言い換えれば、私たちは何年もの間、30秒ごとに1つのMySQLテーブルのスナップショットを撮ろうとしているのです。毎回同じテーブルになり、約10列{x} x 1000行{y}になります(約50KB)。したがって、もしそうなら、30秒ごとに50KBのテーブルのスナップショットを撮りたいと思います。

したがって、これは次の問題を引き起こします:無限の量のテーブルを格納する必要性を回避します。 Stack Exchangeに関するさまざまな投稿を読んで、データベースに数百万のテーブルを配置するのはアーキテクチャが悪く、そのような設計ではパフォーマンスが低下することを読んだことがあります。だから私が考えることができる2つの可能なアーキテクチャはここにあります:

  1. 新しいテーブルを作成し、エポック時間を使用して名前を付け、何百万もの新しいテーブルを際限なく作成します(よくありません)。

  2. Epoch_timeとjsonの2つの列を持つ1つのデータベースを作成します。元のテーブルのすべてのスナップショットについて、30秒ごとに、それをjson文字列に変換し、テーブル全体をjson列に格納します。つまり、基本的には、jsonのシリアル化されたテーブルを含む数百万行のデータベースです。

2番は最高のアーキテクチャでしょうか?私が行方不明になるかもしれないより良い方法はありますか?

3
wayofthefuture

デルタ

「スナップショット」しているデータ-どのくらいの頻度で変化しますか?

「デルタ」のみを保存することを検討することをお勧めします。スナップショットの一部がまったく変更されない場合、デルタは空であり、何も格納できません。

過去のある時点でスナップショットを再構築するには、処理にコストがかかります。必要に応じてバージョンを確認し、差分を適用していく必要があります。

デルタを実行する方法は2つあります(順方向または逆方向)。 「進む」場合は、元の(完全な)スナップショットから開始し、希望する時間までデルタを適用します。 「後方」に移動すると、最新のスナップショットが完全であるという利点があります。後退すると、変更が「差し引かれ」ます。

「何年も」と言うので、たとえば、毎日、完全なスナップショットを撮るのが賢明でしょう。次に、特定の30秒のスナップショットを見つけるには、2880を超えるデルタは含まれません。これは明らかに速度とスペースのトレードオフにつながります。完全なスナップショットはかさばりますが、スナップショットの頻度が低いと、「再構築」時間が長くなります。

トリガー

「スナップショット」ではなく、TRIGGERを使用して「監査証跡」を作成します。これは、私が述べた「デルタ」に似ていますが、「30秒ごと」ではなく、継続的であるという点で優れています。私が覚えているケースは、監査証跡に10億行以上ありました。各行には(おおよそ)タイムスタンプ、テーブル名、PRIMARY KEY、およびその行のすべての列の圧縮されたJSONブロブ。あなたのニーズは、そのいくつかのバリアントによってよりよく満たされるかもしれません。

スキーマ

実際のクエリが表示されるまでは、PARTITIONingを使用しないことをお勧めします。これは通常、パフォーマンス上の利点がないためです。

テーブルサイズの制限に関するリンクに1つの数値がありません。64TBは、パーティション化されていない1つのInnoDBテーブルの制限です。

1
Rick James

そのために、上記で言及されていないアプローチについて説明します。通常、これは時間データに使用されます。それがあなたのニーズに合うかどうかはわかりませんが、ここに行きます。アイデアは、begin_timeとend_timeの2つの追加属性を持つオリジナルのコピーを作成することです。

create table ...
( ...
, begin_time timestamp default now() not null -- MySQL timestamp deviates from standard so perhaps some kind of datetime is better 
, end_time timestamp -- null means current row
)

ロードプロセスでは、各行が現在の行と比較され、何も変更されていない場合は無視されます。現在の行の何かが変更された場合、end_timeがnow()に設定され、新しい行がbegin_time now()で挿入されます。

特定の「行」の傾向は簡単で、行が特定の時点でどのように見えたかを調べることもできます。

1
Lennart

既存のテーブルのすべての列だけでなく、スナップショットが開始された時間の値に設定された時間列も含む、新しいテーブルを作成します。既存のファクトのセットについて格納する新しいファクトを追加します(理想的には、各テーブルに1種類のファクトを格納する必要があります)。時間列の値は、各スナップショットを識別します。

テーブル全体に対してクエリを実行する必要がある場合、それは実用的なディスクIO問題です。しかし、DBからのプレーンな古い列にデータを保持することにより、使用される列にインデックスを追加できますこれらの時間のかかるクエリによるものです。情報の集計データを保持する必要がある場合は、ディスクIOが大きいという問題があります。答えは、更新時にこれらの集計を実行するビューを設計することです。 、毎回のデータセット全体を調べるのではなく、中間履歴データが維持されます。DBにはできるだけ大きなサイズを維持してくださいIO.

大きなテーブルは、メモリとハードドライブの問題になる可能性があります。テーブルの小さな部分以上にアクセスする必要があり、大きなクエリを管理するために人間のタッチが必要になる場合任意のデザイン。 MySQL、OTOHは非常に大きなテーブルで問題ありません。多数のテーブルまたはJSONストアで過度に複雑にすると、効果がありません。また、履歴クエリを実行する必要がある場合は、戻ってくる可能性があります。

ただし、実装では最終的にパーティション化が必要になる場合があります。 DBまたはテーブルに関連する制限に到達し始めたら、パーティショニングを決定します。 将来には、最適な方法を決定するための十分な情報があります。 InnoDBを使用すると、そのような制限に到達できない可能性があります。同様に、設定によっては、1つの大きなテーブルだけでなく、多くのテーブルでそのような制限に達する可能性があります。 http://dev.mysql.com/doc/refman/5.0/en/table-size-limit.html

0

私はこのデータをMySQLではなく、jSQLとしてNoSQLシステムに保存します。この種の問題は、そのアーキテクチャにとって非常に大きなものです。 MySQLよりもはるかに拡張性に優れています。

さらに、実際のデータをクエリ可能にする必要がない場合は、ストリームをDBに保存する前にさらに7Zipします。スペースを無駄にするだけの理由はありません。

0
TizzyD