毎秒2000行の新しい行が挿入されるMySQLデータベースがあります。これらの行は、その特定の時点でのセンサーの値を示します。
計画は、chart.jsを使用してこのデータをグラフィカルな表現にすることです。もちろん、すべてのデータポイントを表示しても意味がなく、非常に遅いクエリになります。
私の質問は、このような状況でとるべき適切なルートは何ですか?これが私の考えです:
必要なデータ解決は、その日の1分間隔、15分間隔、30分間隔、1時間間隔、および1日の値の移動平均であると想定しています。
このアプローチを使用すると、整頓された状態を保つことができ、データをグラフィカルな表現で簡単に表示できます。ここに問題が表示されます:
うさぎの穴が深すぎるかもしれません。私はあなたが持っているかもしれないどんな良い読みもします。
Yurセットアップのいくつかの提案
DBセットアップ
1)一時(ステージング)テーブルを使用して、新しいレコードを収集します。できれば、 insert timestamp を使用して、このテーブルをrange
パーティションに最も細かい集計間隔(分など)で分割する必要があります。測定のタイムスタンプ(センサータイムスタンプと呼ばれる)とは逆のタイムスタンプを挿入することは、区別することが重要です。以下の説明を参照してください。
2)詳細テーブルを、パーティションキーとして使用する同じパーティションスキーマで定義しますセンサータイムスタンプ
3)定義集約テーブルが必要であり、センサータイムスタンプで分割されます。必要なレベルを注意深く確認してください。これは要求されたレポートでは定義されていませんが、パフォーマンスを使用してデータを収集できます。
例えば。 30分のレベルは、 15分のレベルから効果的にクエリできるため、やりすぎのようです。
処理中
1分に1回実行されるバックグラウンドジョブは、開始テーブルの1つのパーティションを処理します(つまり、1分 delta )および
詳細テーブルにすべての行を挿入します
ステージテーブルから計算された delta ですべての集計テーブルを更新します
ここでは注意が必要です。カウント、合計、平均は問題ありませんが、distinct
カウントの場合、推定データのみを生成する HyperLogLog の実装を使用する必要があります。
遅延したデータエントリを処理する必要があるかどうかも確認する必要があります。つまり、 delta にも古いセンサーのタイムスタンプ。これらのタイムスタンプに関連するすべての集約間隔を refresh する必要があります。
例:10:01に挿入されたプロセスデータでは、oldes sensortエントリは09:59であるため、3分の集約(09:59、10:00および10:01)および2つの15分の集約(9:45および10:00)など.
毎日の締めくくり
delta 処理の不正確性に対処するために(上記のHyperLogLogを参照。ただし、他のすべての種類を含む)、定期的に集計の最後の部分を削除し、詳細テーブルから正確に再計算できます。
これにより、「エラーの蓄積」の問題が解消されます。この概念は Lambdaアーキテクチャ とも呼ばれます。
履歴を保持
すべてのテーブルには、ローリングウィンドウポリシー、つまりデータが保持される期間が定義されています。
集約されたテーブルは、レポート要件によって制御されます
詳細テーブルは、 backup として孤独に使用されています。何か問題が発生した場合、集約されたデータを回復する可能性が(限定的に)あります。したがって、経済的に十分意味のある限り設定してください。
古いデータはDROP PARTITION
のみを使用して削除されます(削除は不可)
開始テーブルに cycle パーティショニングを適用できます。つまり、日付コンポーネントではなく、時間のみをパーティションキーとして使用します。これにより、パーティションのメンテナンスが簡略化されます。代わりにTRUNCATE PARTITION
を使用してデータを削除します。
レポート
集計は毎分1回行われます。これは、ロウズ集計が常に一貫していることを意味します。反対に、最後の15分の集計は、 incomplete になり、数分のデータしか含まれません。
この問題を処理するには、 normalizing の概念を設計する必要があります。 Nice ではありません。 successfullイベントの数が1時間の最後の四半期に大幅に減少したことを確認してください。
幸運を!
私が目にする主な問題:
DELETEs
は大きなコストです。そう...
古いデータを削除しますか?その場合、おそらく1分のテーブルについてのみ心配する必要があります。他のテーブルは非常に小さいので、「永久に」保持できます。これを行うには、PARTITION BY RANGE
を使用して、保持期間に基づいてパーティション数を決定します。 http://mysql.rjweb.org/doc.php/partitionmaint を参照してください。 (DROP PARTITION
は、同等のDELETE
よりもmuch高速で、侵襲性が低くなります。)
高速取り込み-上記のヒントで労力を十分に削減できなかった場合は、 http://mysql.rjweb.org/doc.php/staging_table を参照してください。
その他のヒント:
PRIMARY KEY
がありますが、適切な「自然インデックス」がある場合はAUTO_INCREMENT
を使用しないでください。TINYINT SIGNED
(1バイト)を使用できます。 10度または100度を取得するには、10を掛けてSMALLINT SIGNED
(2バイト)を使用してスケーリングするのが最適な場合があります。 Eschew FLOAT
(4バイト)、特にDOUBLE
(8バイト)は、本当に必要な場合を除きます。TINYINT UNSIGNED
にはSMALLINT UNSIGNED
またはsensor_id
を使用します。センサーの名前/場所/バルクIDなどへの/からの別のテーブルマッピングがあります。