MySQLを使用して定期的に100 GB以上のテーブルで多方向結合を行いますか?


11

背景
適切にスケーリングできるようにしたいWebアプリケーションを作成しました。私はGoogleやTwitterではないことを知っていますが、私のアプリはユーザーごとにかなり大量のデータを使用するため、かなり高いデータ要件があります。後ですべてを再構築する必要なく、適切に拡張できるように準備したいと思っています。

私はデータベースの専門家ではなく、ソフトウェア開発者だと思っています。それが私がここに投稿する理由です。うまくいけば、より多くのデータベースの専門知識を持つ誰かが私に助言を与えることができます。

比較的多数のユーザーがいるが、Facebookの番号のようなものは何もないので、私は次のようなDBを期待しています。

1つの「大きなテーブル」:

  • 2億5000万件のレコード
  • 20カラム
  • 約100 GBのデータ
  • インデックス付きのbigint(20)外部キーがあります
  • インデックス付きのvarchar(500)string_id列があります
  • int(11)の「値」列があります

他の4つのテーブル:

  • それぞれ1,000万件のレコード
  • それぞれ約2〜4 GBのデータ
  • これらの各テーブルには4〜8列があります
  • 1つの列はdatetime date_createdです
  • 1つの列はvarchar(500)string_id列です
  • これらの各テーブルから1つまたは2つの列が結合で選択されます

これらのテーブルの1つは平均を格納するために使用されます-そのスキーマはbigint(20)id、varchar(20)string_id、datetime date_created、float average_valueです。

私がやりたいこと -2つの比較的高価なクエリ:

  1. 新しい平均値を計算します。

    • 外部キーを使用して、大きなテーブルから最大数百万の個別のレコードを選択します。
    • string_idでグループ化して、新しい平均を計算します。
    • 結果を平均表に挿入します。
    • 現在作成されているように、このクエリは2つの結合を使用します。
  2. ユーザーにサービスを提供するための非正規化された読み取り専用レコードを作成します。

    • 外部キーを使用して、大きなテーブルから1,000〜40,000レコードのいずれかを選択します。
    • 文字列id列を持つ最新のレコードで他の4つのテーブルのそれぞれと結合します。
    • 結果を非正規化テーブルに挿入します。
    • これらのレコードは、フロントエンドがユーザーに情報を表示するために使用されます。
    • 現在作成されているように、このクエリは4つの結合を使用します。

ユーザーからのリクエストを処理するリアルタイムのフロントエンドDBサーバーに結果をプッシュするバッチバックエンドデータベースで、これらの高価なクエリをそれぞれ実行する予定です。これらのクエリは定期的に実行されます。頻度はまだ決めていません。平均的なクエリは、おそらく1日に1回行うことができます。非正規化クエリは、より頻繁に、おそらく数分ごとに実行する必要があります。

これらの各クエリは現在、MySQLの「ビッグテーブル」に100Kレコードのデータセットを持つ非常にローエンドのマシンで数秒で実行されます。私のスケーリング能力とスケーリングのコストの両方が心配です。

質問

  1. このアプローチは健全に見えますか?全体像の観点から、明らかに問題はありますか?
  2. RDBMSは適切なツールですか、それともHadoopファミリのような他の「ビッグデータ」ソリューションを検討する必要がありますか?データは構造化されており、リレーショナルモデルにうまく適合しているため、RDBMSを使用する傾向があります。ただし、ある時点で、RDBMSを使用できなくなる可能性があるというのが私の理解です。本当?このスイッチが必要になるのはいつですか?
  3. うまくいきますか?これらのクエリは妥当な時間内に実行できますか?クエリ#1はおそらく数時間待つことができますが、クエリ#2は数分で完了するはずです。
  4. ハードウェアの観点から何を考慮すべきですか?RAMとCPUのボトルネックになる可能性があるのは何ですか?RAMにインデックスを保持することが重要だと思います。他に考慮すべきことはありますか?
  5. ある時点で、おそらくデータを分割して複数のサーバーを使用する必要があります。私のユースケースはすでにそのカテゴリにあるように見えますか、それともしばらくの間、1台のマシンを垂直方向にスケーリングできますか?これはデータの10倍で動作しますか?100倍?

これは完全に答えるのは難しいです。おそらく、MySQLクエリのパフォーマンス特性全般について調査した方がいいので、何が期待できるかがわかります。もちろん、常にできることの1つは、20 GBのディスクをサーバーに配置して、3 GB /秒程度で読み取ることができるようにすることです。しかし、ソフトウェアのみの完全な回答を求めていると思います。
usr

回答:


4

より多くのデータを積み上げてベンチマークを試みましたか?10万行は重要ではありません。250Mまたは500Mを試して、ボトルネックの場所を確認して対処する必要があると思います。

RDBMSは、制限に細心の注意を払い、システムの強みを試してみると、多くのことができます。それらはいくつかの点で非常に優れており、他の点ではひどいので、それが適切であることを確認するために実験する必要があります。

一部のバッチ処理ジョブでは、フラットファイルに勝てず、データをRAMにロードし、一連のループと一時変数を使用してデータを破壊し、結果をダンプできません。MySQLは決してそのような速度に対応することはできませんが、適切に調整して正しく使用すれば、1桁以内になる可能性があります。

データを分割する方法を調査する必要があります。クロスリンクの方法が多すぎて分割できない1つの大きなデータセットがありますか、それとも分割するのに自然な場所がありますか?それを分割できる場合、行の山全体を1つのテーブルにすることはできませんが、潜在的に多くの大幅に小さいテーブルになる可能性があります。インデックスがはるかに小さい小さなテーブルは、パフォーマンスが向上する傾向があります。

ハードウェアの観点からは、プラットフォームのパフォーマンスをテストする必要があります。時には記憶が不可欠です。それ以外の場合は、ディスクI / Oです。これは、実際にデータをどのように処理しているかによって異なります。CPU使用率に細心の注意を払い、問題がどこにあるかを知るために高レベルのIO待機を探す必要があります。

可能な限り、データを複数のシステムに分割してください。勇気がある場合はMySQL Clusterを使用できます。または、それぞれが完全なデータセットの任意の部分を格納するMySQLの多くの独立したインスタンスを起動して、意味のあるパーティションスキームを使用できます。


@tadmanアドバイスありがとうございます。実際に試してみることに代わるものはないことに気づきました。最初に自分のアプローチに明らかに問題がないことを確認したかったので、2億5000万行でベンチマークしていません。ないようです。さらに、それだけ多くのデータを取得し、いくぶん現実的な方法でそれを行うことは、私がまだ解決する方法を理解していない課題です。データを分割する方法はいくつかあります。次に、データを増やして、さまざまなチェックポイント(1M、10M、100Mなど)でどのように機能するかを確認します
xnickmx

1

要約表。

毎日、その日のデータの集計情報を計算します。それを「要約」表に入れます。それらに対してクエリを実行します。簡単に10倍の速さ。

詳細な議論のために、提供してください

  • SHOW CREATE TABLE(現状のまま)
  • テーブルサイズ(あなたが言及した)
  • 提案されたSELECT

明らかなこと...

  • BIGINTが保証されることはほとんどありません。8バイトかかります。INT UNSIGNEDは4をとり、0〜40億の値を許可します。そしてMEDIUMINTなどがあります。
  • 「ファクト」テーブルの複数のインデックスは、特にINSERTの場合、通常、重大なパフォーマンスの問題です。そこに問題がありますか?
  • DATETIMEは8バイトです。タイムスタンプは4
  • 明示的なFOREIGN KEY CONSTRAINTSは適切ですが、コストがかかります
  • JOINはパフォーマンスの問題である場合とそうでない場合があります。SELECTとCREATEを見る必要があります。
  • 100 GBは、「大きな」MySQLデータベースに適したサイズです。Hadoopなどがなくても機能する可能性があると思います。このようなデータベースを1つ処理します。ほとんどのUIページは、データがかなり複雑であっても、1秒以内に応答します。
  • ある時点でデータを「パージ」しますか?(これにより、PARTITIONの主な使用例になります。)

「より小さく->よりキャッシュ可能->より速く


0

フロントエンドデータを提供するために、常に大量の挿入がある場合を除き、トリガーを使用してマテリアライズドビューに挿入し、バックエンドとの同期を維持しながらデータを提供するように最適化することはできません。もちろん、これらのトリガーでは、結合などを最小限に抑える必要があります。私が使用した戦略の1つは、これらの挿入/更新を中間テーブルにキューイングし、後で1分ごとに送信することです。4 GBのレコードよりも1つのレコードを送信する方がはるかに簡単です。4 GBのデータは、探しているレコードをすばやく見つけることができても、ストリーミングに長い時間がかかります。

タッドマンに同意します。最善の方法は、必要な種類のシステムで期待している種類のデータでプロファイルを作成することです。


投稿で述べたように、ビューは数千万のレコードを持つテーブル全体で4つの結合を使用するクエリに依存しているため、マテリアライズドビューがどのように役立つかはわかりません。
xnickmx 2012

このサイズのデータ​​ベースでは、トリガーの速度が不十分な場合があります。1秒あたり何回のINSERTが発生していますか?
リックジェームズ

1
@xnickmx挿入/更新がそれほど多くない場合、トリガーを使用すると、非正規化されたデータの同期を簡単に実行できます。挿入/更新の速度を上げる必要がある場合は、blog.shlomoid.com / 2008/04 / …のようにキューイングするか、独自に焼き付けます。この方法では、トリガーが起動したときに新しいデータがわかっているという事実を利用して、txの一部として非正規化できるため、既存の1億行のテーブルに対して結合して新しいデータを取得する必要はありません。または後で非正規化するためにキューに入れます。
wes.stueve 2012

@RickJames同意する。この種の戦略の挿入の量とそれらが処理する必要のある速度を考慮する必要があります。
wes.stueve 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.