73億行の市場データを保存する方法(読み取るように最適化)?


84

1998年以降の1000株の1分間のデータのデータセットがあり、その合計(2012-1998)*(365*24*60)*1000 = 7.3 Billionは行の周りにあります。

ほとんど(99.9%)は、読み取り要求のみを実行します。

このデータをデータベースに保存するための最良の方法は何ですか?

  • 7.3B行の1つの大きなテーブル?
  • 1000テーブル(銘柄記号ごとに1つ)、それぞれ730万行?
  • データベースエンジンの推奨事項はありますか?(Amazon RDSのMySQLを使用する予定です)

私はこれほど大きなデータセットを扱うことに慣れていないので、これは私が学ぶ絶好の機会です。私はあなたの助けとアドバイスに感謝します。

編集:

これはサンプル行です:

「XX」、20041208、938、43.7444、43.7541、43.735、43.7444、35116.7、1、0、0

列1は銘柄記号、列2は日付、列3は分、残りは始値-高値-安値-終値、出来高、および3つの整数列です。

ほとんどのクエリは、「2012年4月12日12:15から2012年4月13日12:52までのAAPLの価格を教えてください」のようになります。

ハードウェアについて:Amazon RDSを使用する予定なので、柔軟に対応できます。


5
予想される典型的なクエリを説明してください
William Pursell 2012年

10
「MongoDBはWebスケールなので、使用する必要があると思います。」
ta.speot.is 2012年

8
おそらく、銘柄記号で分割された1つの大きなテーブルが必要です。
ta.speot.is 2012年

1
データセットは巨大です!データマイニングと分析を検索して、見つけたものを確認することをお勧めします。
マイクパーセル

2
そして、単一のテーブルを持つ「標準RDBMS」はこれには不十分ですか?(私は数百万を扱っているだけですが、「私のために働いています」。試してみてください。必要に応じてインデックス/クラスター/パーティションを忘れないでください。)

回答:


30

クエリとハードウェア環境について教えてください。

Hadoopを使用してNoSQLに移行したいと思うでしょう。並列処理を利用できる限り、など。

更新

さて、なぜですか?

まず、クエリについて質問したことに注意してください。ワークロードがどのようなものかを知らずに、これらの質問に答えることはできません。もちろん、答えることもできません。(偶然にも、これに関する記事がまもなく登場しますが、今日はリンクできません。)しかし、問題の規模から、Big OldDatabaseから離れることを考えさせられます。

  • 同様のシステムでの私の経験は、アクセスが大きなシーケンシャル(ある種の時系列分析を計算する)または非常に柔軟なデータマイニング(OLAP)のいずれかになることを示唆しています。シーケンシャルデータは、シーケンシャルでより適切かつ高速に処理できます。OLAPとは、多くのインデックスを計算することを意味します。これには、多くの時間または多くのスペースが必要になります。

  • ただし、OLAPの世界で多くのデータに対して効果的に大規模な実行を行っている場合は、列指向のアプローチが最適な場合があります。

  • ランダムなクエリを実行する場合、特に相互比較を行う場合は、Hadoopシステムが効果的です。どうして?なぜなら

    • 比較的小さなコモディティハードウェアで並列処理をうまく活用できます。
    • また、高い信頼性と冗長性をより適切に実装できます
    • これらの問題の多くは、MapReduceパラダイムに自然に役立ちます。

しかし、実際には、あなたのワークロードについて知るまで、決定的なことを言うことは不可能です。


7
ここで「NoSQL」にはどのような利点がありますか?従来のRDBMSで単一の大きなテーブルを使用しないのはなぜですか?(正しいインデックスなどで)誰もが「NoSQL」、「NoSQL」、「NoSQL」に行きますが...なぜですか?

5
私の提案は、Apache Accumuloを使用したNoSQLアプローチでもあると言わざるを得ません(これは個人的な好みです)。データセットが小さく(Accumuloの場合)、必要なクエリのタイプは、分散イテレータスタックを使用する場合に完全に適しているようです。
バイナリオタク2012年

拡大された答えをありがとう。私はそれを+1することができます。

1
ここでのコメントのいくつかは私を混乱させることがあります。「意味のないデータベースを使用する場合は-1?」全体の答えは、従来のデータベースに反対しています。
チャーリーマーティン

51

したがって、データベースは、絶えず変化する大規模で複雑なスキーマがある状況向けです。単純な数値フィールドでいっぱいの「テーブル」は1つだけです。私はそれをこのようにします:

レコード形式を保持するためのC / C ++構造体を準備します。

struct StockPrice
{
    char ticker_code[2];
    double stock_price;
    timespec when;
    etc
};

次に、sizeof(StockPrice [N])を計算します。ここで、Nはレコードの数です。(64ビットシステムの場合)数百ギガで、50ドルのHDDに収まるはずです。

次に、ファイルをそのサイズに切り詰めて(Linuxの場合はmmap、Windowsの場合はCreateFileMappingを使用して)メモリに格納します。

//pseduo-code
file = open("my.data", WRITE_ONLY);
truncate(file, sizeof(StockPrice[N]));
void* p = mmap(file, WRITE_ONLY);

mmapされたポインターをStockPrice *にキャストし、配列に入力するデータを渡します。mmapを閉じると、後で再びmmapできるファイル内の1つの大きなバイナリ配列にデータが含まれるようになります。

StockPrice* stocks = (StockPrice*) p;
for (size_t i = 0; i < N; i++)
{
    stocks[i] = ParseNextStock(stock_indata_file);
}
close(file);

これで、任意のプログラムから読み取り専用で再度mmapできるようになり、データをすぐに利用できるようになります。

file = open("my.data", READ_ONLY);
StockPrice* stocks = (StockPrice*) mmap(file, READ_ONLY);

// do stuff with stocks;

これで、メモリ内の構造体配列のように扱うことができます。「クエリ」が何であるかに応じて、さまざまな種類のインデックスデータ構造を作成できます。カーネルはディスクとの間でデータを透過的に交換するので、めちゃくちゃ高速になります。

特定のアクセスパターン(たとえば、連続した日付)があると予想される場合は、配列をこの順序で並べ替えて、ディスクに順番にヒットするようにするのが最適です。


11
ハードディスクの代わりにSSDに置くために数百を費やしてください。ランダム読み取りは約100倍高速です。またはラムに10Kを費やします。さらに100倍速い
Stephan Eggermont 2012

1
@Andrew Tomazosありがとう、これは「その」答えです
Pavneet_Singh 2016

1
StockPriceのサイズはchar [4] = 4バイトint = 4バイトshort = 2バイトfloat = 4バイトfloat = 4バイトfloat = 4バイトfloat = 4バイトfloat = 4バイトint = 4バイトint = 4バイトint = 4バイト------------ 42バイト約3,066億バイト= 〜285.5435013771057 GBメモリ...それで頑張ってください
ZagNut 2016

3
@ZagNut:300GBの物理メモリが必要であるという意味の場合、それは正しくありません-mmapはすべてをメモリにコピーするのではなく、必要に応じてページイン/ページアウトします(スワップファイルと同じ方法で) 。
アンドリュートマゾス

33

1000株の1分間のデータのデータセットがあります[...]ほとんどの場合(99.9%)、読み取り要求のみを実行します。

時間ベースの数値データを1回保存し、何度も読み取ることは、「時系列」と呼ばれるユースケースです。その他の一般的な時系列は、モノのインターネットのセンサーデータ、サーバー監視統計、アプリケーションイベントなどです。

この質問は2012年に行われ、それ以来、いくつかのデータベースエンジンが時系列を管理するための機能を開発してきました。InfluxDBで素晴らしい結果が得られましたオープンソースで、Goで記述され、MITライセンスで。

InfluxDBは、時系列データを格納およびクエリするように特別に最適化されています。時系列を保存するのに最適であるとしばしば宣伝されているCassandraよりもはるかに優れています。

InfluxDBとCassandraのクエリ速度

時系列の最適化には、特定のトレードオフが含まれていました。例えば:

既存のデータの更新はめったに発生せず、論争のある更新は発生しません。時系列データは主に、更新されることのない新しいデータです。

長所:更新へのアクセスを制限すると、クエリと書き込みのパフォーマンスが向上します

短所:更新機能が大幅に制限されています

オープンソースのベンチマーク

InfluxDBは、3つのテストすべてでMongoDBを上回り、書き込みスループットが27倍になり、使用するディスク容量が84倍少なくなり、クエリ速度に関しては比較的同等のパフォーマンスを実現しました。

InfluxDBとMongoDBのディスク上のストレージ要件と圧縮

クエリも非常に簡単です。行がのよう<symbol, timestamp, open, high, low, close, volume>に見える場合、InfluxDBを使用すると、それだけを保存して、簡単にクエリを実行できます。たとえば、最後の10分間のデータについて:

SELECT open, close FROM market_data WHERE symbol = 'AAPL' AND time > '2012-04-12 12:15' AND time < '2012-04-13 12:52'

ID、キー、および作成する結合はありません。興味深い集計をたくさん行うことができます。PostgreSQLのようテーブル垂直方向に分割したり、MongoDBのようにスキーマを秒の配列に歪めたりする必要はありません。また、InfluxDBは非常によく圧縮されますがPostgreSQLは、使用しているデータの種類に対して圧縮を実行できません


17

さて、これは他の答えから少し離れていますが...固定レコードサイズのファイルシステム(おそらくファイルごとに1つのストック)にデータがある場合、データを取得できるように感じます本当に簡単です。特定の在庫と時間範囲のクエリが与えられると、適切な場所を探し、必要なすべてのデータをフェッチし(正確に何バイトかがわかります)、データを必要な形式に変換できます(これにより、ストレージフォーマットに応じて非常に迅速に)そしてあなたは離れています。

Amazonストレージについては何も知りませんが、ファイルへの直接アクセスのようなものがない場合は、基本的にBLOBを使用できます。大きなBLOBのバランスを取る必要があります(レコードは少なくなりますが、それぞれに必要なデータよりも多くのデータを読み取る可能性があります)。時間)小さなblobを使用します(レコードが多いほどオーバーヘッドが大きくなり、おそらくそれらを取得するための要求が多くなりますが、毎回返される無駄なデータは少なくなります)。

次に、キャッシュを追加します(たとえば、さまざまなサーバーに処理するさまざまなストックを与えることをお勧めします)。ほとんどの場合、メモリから提供できます。十分な数のサーバーに十分なメモリを確保できる場合は、「オンデマンドでロード」の部分をバイパスして、起動時にすべてのファイルをロードするだけです。これにより、起動が遅くなりますが、作業が簡素化されます(特定の在庫に対して常に2台のサーバーを用意できる場合を除いて、フェイルオーバーに明らかに影響します。これは役に立ちます)。

レコードごとに銘柄記号、日付、または分を保存する必要がないことに注意してください。これらは、ロードするファイルとファイル内の位置に暗黙的に含まれているためです。また、各値に必要な精度と、それを効率的に保存する方法も検討する必要があります。質問で6SFを指定しました。これは、20ビットで保存できます。3つの20ビット整数を64ビットのストレージに格納する可能性があります。それをlong(または64ビット整数値が何であれ)として読み取り、マスキング/シフトを使用して3つの整数に戻します。もちろん、使用するスケールを知る必要があります。一定にできない場合は、スペアの4ビットでエンコードできます。

他の3つの整数列がどのようなものかについてはまだ述べていませんが、これら3つの列についても64ビットを使用できれば、レコード全体を16バイトで格納できます。これは、データベース全体でわずか110GBですが、それほど多くはありません...

編集:考慮すべきもう1つのことは、おそらく在庫は週末、または実際には一晩で変化しないということです。株式市場が1日8時間、週5日しか開いていない場合、必要な値は168ではなく40です。その時点で、ファイルに含まれるデータは約28GBになります...おそらく当初考えていたよりもはるかに小さいです。メモリにそれだけのデータがあることは非常に合理的です。

編集:このアプローチがここに適している理由の説明を見逃したと思います:データの大部分(株式相場表示、日付と時刻)について非常に予測可能な側面があります。ティッカー(ファイル名として)1回表現し、日付/時刻をデータの位置に完全に暗黙的に残すことで、大量の作業を削除します。これは、aString[]とaの違いに少し似てMap<Integer, String>います。配列インデックスは常に0から始まり、配列の長さまで1ずつ増加するため、迅速なアクセスとより効率的なストレージが可能になります。


繰り返しますが、これは彼がデータをどのように使用しているかによって異なります。彼のクエリが特定のデータを全面的にプルすることである場合(銘柄記号ごと)、これにはすべてのファイルの読み取りと、それぞれから正しいデータをプルするための特定の日付エンコーディングが必要になります。または、週に最高のパフォーマンスの株が必要な場合は、すべてのレコードを読み取って並べ替えて比較する必要があるこの種の設定では悪夢になります。このような情報がなければ、これは固定ストレージ用であると推測できます。おそらく、ある時点でレポートDWにフィードするバルクDWとして(ETLソース)。
Wolf5370 2012年

2
@ Wolf5370:はい、確かにクエリがどうなるかを知る必要がありますが、質問から少なくともいくつかの兆候があります: 'ほとんどのクエリは「2012年4月12日12:15からAAPLの価格を教えてください」のようになります。 2012年4月13日12' :52何を知っていいだろう。他の相対頻度と性能要件のクエリは次のようになり、同様に。
ジョンスキート

@JonSkeet実際にはワークロードに依存しますが、この種のシステムに関するある程度のドメイン知識があり、「1つの範囲で1つの株式を選択する」ことはめったにありません。「このポートフォリオでこの範囲の株式を選択する」ことがはるかに多いです。 &beta;を計算してから、この可能な株式のリストを試して、&beta;が何であるかを確認してください。」そのため、OLAPのようなものに向かってあなたを駆り立てます。
チャーリーマーティン

2
@CharlieMartin:ええと、私は質問が述べていることをただ通り過ぎていました。ただし、基本的にすべてをメモリに(いくつかのサーバーで)取得できる場合は、それでも非常に簡単です。各サーバーにポートフォリオ内の関連する株式を尋ねてから、結果をまとめます。データの既知の側面(1分に1回、ただし週末や夜間は使用しない)を使用することについての私のポイントは、すべてをメモリに保存することの難しさを大幅に軽減するという点で依然として役立つと思います。
Jon Skeet 2012年

この議論は、「表現はプログラミングの本質である」というフレッド・ブルックスの引用と、ベントレーの「プログラミングパール」の関連する問題を思い出させます。
CS

14

HDF5は、潜在的なアプリケーションの1つとして、株式データの時系列ストレージを使用して特別に設計されたと理解しています。仲間のスタッカーは、HDF5が大量のデータ(染色体物理学)に適していることを示しています。


2
特定のソリューションの場合は+1。しかし、私はSQL DQL(ほとんどの部分)とそれが提供する柔軟性が大好きです...「階層ビュー」から抜け出すためにHDF5で何が必要かわかりません。

4

これは、無料のオープンソースプロジェクトであるOLAP分析に適したMicrosoft SQL Server2012データベースの上にMarketDataServerを作成する試みです。

http://github.com/kriasoft/market-data


ええ。その特定のプロジェクトが適用可能かどうかはわかりませんが、OPがOLAPまたはデータウェアハウスのファクトテーブル構造を検討することを確実に示唆します。両方のアプローチ(一緒に使用されることもあります)は、非常に多数の行のこの種のデータに対処するように設計されています。しかし、それは彼らが実行しようとしている分析の種類に本当に依存します。
AaronLS 2014

4

まず、1年に365取引日はなく、休日は52週末(104)= 250 x誰かが言ったように実際の営業時間であり、記号を主キーとして使用することはお勧めできません。記号が変わるので、記号(char)とともにk_equity_id(数値)を使用します。記号はこのAまたはGAC-DB-B.TOのようになり、価格情報のデータテーブルにあるので、推定値は7.3になります。 14年間でシンボルあたり約170万行しかないため、10億は大幅に計算されすぎています。

k_equity_id k_date k_minute

およびEODテーブル(他のデータの1000倍で表示されます)

k_equity_id k_date

次に、OHLCを分単位のデータでEODテーブル(1日の終わり)と同じDBテーブルに保存しないでください。1年以上にわたってpnfまたは折れ線グラフを見たい人は、byにまったく関心がないからです。分の情報。


3

特定の問題に理想的だと思うapachesolrを確認することをお勧めします。基本的に、最初にデータにインデックスを付けます(各行は「ドキュメント」です)。Solrは検索用に最適化されており、日付の範囲クエリをネイティブにサポートしています。あなたの名目上の質問、

"Give me the prices of AAPL between April 12 2012 12:15 and April 13 2012 12:52"

次のようなものに変換されます:

?q=stock:AAPL AND date:[2012-04-12T12:15:00Z TO 2012-04-13T12:52:00Z]

「stock」が銘柄名であり、「date」がインデックス作成の入力データの「date」列と「minute」列から作成された「DateField」であると仮定します。Solrは非常に柔軟性があり、私はそれについて十分に良いことを言うことができません。したがって、たとえば、元のデータのフィールドを維持する必要がある場合は、クエリ(またはフィルター)の一部として「DateField」を動的に作成する方法を見つけることができます。


また、あなたのSolrインスタンスを設定するためにアマゾンEC2を使用することができます... lucidimagination.com/blog/2010/02/01/...
aliasmrchips

3
SOLRは検索に最適ですが、インデックスにデータを入力するには、データをどこかに保存する必要があります。
マイクパーセル

本当。ビクターPはどこかにデータがあり、インデックスを作成する必要があると思います。これには追加のリソースが必要になります...ただし、提案されているすべてのアプローチも同様です。
aliasmrchips 2012年

@aliasmrchips:InfluxDBアプローチの方が優れていると思います。効率的に保存し(高スループット、Mongoより80倍優れた圧縮)、クエリも簡単です。
ダンダスカレスク2016

3

主要なRDBMSならどれでもこれを処理できると思います。アトミックレベルでは、正しいパーティション化を備えた1つのテーブルが妥当と思われます(固定されている場合はデータ使用量に基づくパーティション化-これはシンボルまたは日付のいずれかである可能性があります)。

アトミックレベルより上でより高速にアクセスするために、集約テーブルの構築を検討することもできます。たとえば、データが日中のものであるが、データが週レベルまたは月レベルで返されることが多い場合、これは集計テーブルで事前に計算できます。一部のデータベースでは、これはキャッシュされたビュー(さまざまなDBソリューションのさまざまな名前-基本的にはアトミックデータのビューですが、実行されると、ビューは固定の一時テーブルにキャッシュ/強化されます-これは、後続の一致クエリに対してクエリされます)を介して実行できます。これは、メモリ/ディスク領域を解放するために間隔を置いて削除できます)。

私たちは、データの使用法に関するいくつかのアイデアであなたをもっと助けることができると思います。


3

遅いソリューションを、メモリモデルで最適化された単純なものと比較する必要があります。非圧縮の場合、256GBのRAMサーバーに収まります。スナップショットは32Kに収まり、日時と在庫の位置にインデックスを付けるだけです。次に、特殊なスナップショットを作成できます。1つを開くと、前のスナップショットを閉じることがよくあるためです。

[編集]データベース(rdbmsまたはnosql)を使用することが理にかなっているのはなぜだと思いますか?このデータは変更されず、メモリに収まります。これは、dbmsが価値を付加できるユースケースではありません。


実際には、いくつかの理由があります。特に、256 GBのメモリがある場合は、一時スペースやオペレーティングシステムなどのスペースがあれば便利です。次に、チェックポインティング、ロギング、フォールトトレランスなどの問題があります。中間結果の計算を開始すると、ストレージの管理が必要になります。RDBMSが最良の選択ではないことに同意しますが、「大きなアレイをメモリにロードする」よりも賢いものが絶対に必要です。
チャーリーマーティン

ほぼ静的なデータの場合、チェックポインティング、ロギング、およびフォールトトレランスは非常に簡単です。普及しているスタイルのソリューションに最適のように聞こえます
Stephan Eggermont 2012

繰り返しになりますが、アプリケーションの知識がないと確実に言うことはできませんが、一般に、アプリケーションは思ったほど静的ではありません。これは、結果セットを維持したいため、また、でコストのかかる計算を行っているためです。 、チェックポイントおよび事前計算された部分的な結果。
チャーリーマーティン

2

ハードウェアをお持ちの場合は、MySQLClusterをお勧めします。使い慣れたMySQL / RDBMSインターフェースを取得し、高速で並列の書き込みを取得します。ネットワークの待ち時間のため、読み取りは通常のMySQLよりも遅くなりますが、MySQL ClusterとNDBストレージエンジンの動作方法により、クエリと読み取りを並列化できるという利点があります。

ただし、十分なMySQLClusterマシンとそれらのそれぞれに十分なメモリ/ RAMがあることを確認してください-MySQLClusterは非常にメモリ指向のデータベースアーキテクチャです。

または、読み取り/書き込みへのKey-Value / NoSQLインターフェースを気にしない場合はRedis。Redisに十分なメモリがあることを確認してください-読み取りと書き込みに超高速で、基本的なクエリを実行できますが(RDBMS以外)、インメモリデータベースでもあります。

他の人が言っているように、実行するクエリについてもっと知ることは助けになります。


2

データを列テーブル/データベースに保存する必要があります。VerticaやGreenplumなどのデータベースシステムは列指向データベースであり、SQLServerで列テーブルが使用できるようになったと思います。これらはSELECT、非常に大きなデータセットからのingに非常に効率的です。また、大規模なデータセットのインポートにも効率的です。

無料の列指向データベースはMonetDBです。


1

ユースケースが集約なしで行を単純に読み取ることである場合は、Aerospikeクラスターを使用できます。これは、永続性のためのファイルシステムをサポートするメモリデータベースにあります。SSDにも最適化されています。

ユースケースで集計データが必要な場合は、日付範囲シャーディングを備えたMongoDBクラスターを選択してください。シャードで年バイスデータをクラブできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.