私は、ユーザーが自分で選択したメッセージを受信できることに依存するサービスを開発しています。これらのメッセージは、処理のために送信される前にどこかに保存する必要があります。
現在、それらをpostgresデータベースに格納していますが、適切にスケーリングできないと感じています。
現在のレイアウトは次のとおりです。
ID - MESSAGE - DATE - TIME
DATEおよびTIMEフィールドには、処理のためにメッセージを送信する必要がある日時が保持されます。毎月最初の月曜日にメッセージを送信する必要がある場合、12倍のスペースが必要になるため、これは適切にスケーリングされません。
問題は、処理のためにメッセージを送信するタイミングを表す別の方法が見つからないように見えることです。理想的には、すべての日付を1つの行で表すことができるようになりたいです。
Redisの使用についても検討しましたが、Webフロントエンド用のデータベースが必要になるため、すぐには決定しませんでした。
メッセージストレージを最適化する方法を知っている人はいますか?処理のためにメッセージを送信するタイミングをどのように表すか?
また、これに取り組む方法に関する他の提案も歓迎します。
常に、要件をサポートする標準を探してください。カレンダーイベントの繰り返しをサポートする標準とは何ですか? ICalendar RRULE:
http://en.wikipedia.org/wiki/ICalendar
http://www.kanzaki.com/docs/ical/rrule.html
ルールをプレーンテキストとして保存し、必要に応じて解析するか、データベーススキーマを使用できます。
Perl: http://search.cpan.org/~rfrankel/iCal-Parser-1.16/lib/iCal/Parser.pm
PostgreSQL固有: http://svn.expressolivre.org/contrib/davical/dba/rrule_functions-8.1.sql
パフォーマンスに関しては、マテリアライズドビューを使用して、イベントを計算できます。たとえば、1か月前と1か月前(必要な場合)です。
追加情報: http://www.vertabelo.com/blog/technical-articles/again-and-again-managing-recurring-events-in-a-data-model この記事では、それぞれについて説明し、繰り返されるイベントのあらゆる側面。結論に至る前に必ずお読みください。
Zoltanが指摘したように、何百万もの行がない限り、スケーリングの問題は発生しません。 JavaなどのQuartzのようなものをスケジュールするための多くのライブラリもあります。これらは、繰り返しスケジュールをcronのような式として保存します。上記の例には欠陥があるため、繰り返しが毎週月曜日は52 x number of years the service will go for
。
したがって、日付または繰り返しパターンを保存できます。
メッセージIDの一部を使用して別のテーブルを作成する
表1:id-メッセージ
表2:id-日付
「表2」をその日付でなんとかして整理できるかどうかを確認し、日付を次のようにフォーマットします。
min-hour-dom-mon-wom-dow(dom =月の日、mon =月、wom =週の週、dow =曜日)
数字は「12」、ワイルドカードは「*」、最初は「<」、最後は「>」のように使用できます。
次に、最初に2番目のテーブルをクエリします。2番目と3番目のテーブルを使用することもできます。次に、3番目のテーブルにクエリを実行して2番目のテーブルにメッセージを追加しますが、2番目のテーブルは1か月または1年分だけいっぱいになります。
このインスピレーションはcrontabのスケジュールが機能する方法から生まれました
* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)
質問を正しく理解すると、ユーザーとして特定の日付と繰り返しに「アラーム」を設定して、通知を受け取ることができますか?
一般的に言って、何百万もヒットするまで、通常のSQLデータベースではスケーリングの問題は発生しません。適切なインデックスを使用するだけです。
スキーマを少し最適化することをお勧めします。次に送信する必要があるときに保存するのではなく、最後に送信されたときと再生間隔を保存するだけで、いつ再送信するかを簡単に計算できます。
最初に行うべきことは、メッセージテキストを行外に別のテーブルに格納することです。
それをフェッチするには結合のコストがかかりますが、それは簡単なBツリーインデックスルックアップであり、スケジュールされたイベントを含むテーブルでスキャンする行が狭いという利点が大幅に上回ります。
これを「繰り返し発生するアラーム」または「繰り返し発生するカレンダーイベント」の問題のように考えると、そのようなデータを保存して効率的にクエリする方法についての記述が増えると思います。インデックスに適した格納方法は行の繰り返しを伴う傾向があり、編集と更新が面倒になるため、それは単純ではありません。
テーブルの partitioning を使用できます。
パーティション化とは、論理的に1つの大きなテーブルを小さな物理的な断片に分割することを指します。パーティション化には、いくつかの利点があります。
特定の状況、特にテーブルのアクセス頻度の高い行のほとんどが単一のパーティションまたは少数のパーティションにある場合、クエリのパフォーマンスは劇的に向上します。パーティション分割は、インデックスの先行列の代わりになり、インデックスのサイズが小さくなり、インデックスの頻繁に使用される部分がメモリに収まる可能性が高くなります。
クエリまたは更新が単一のパーティションの大部分にアクセスする場合、テーブル全体に分散したインデックスとランダムアクセス読み取りを使用する代わりに、そのパーティションのシーケンシャルスキャンを利用することでパフォーマンスを改善できます。
パーティションの設計で要件が計画されている場合は、パーティションを追加または削除することにより、一括読み込みと削除を実行できます。 ALTER TABLE NO INHERITとDROP TABLEはどちらも、一括操作よりもはるかに高速です。これらのコマンドは、一括DELETEによって引き起こされるVACUUMオーバーヘッドも完全に回避します。
ほとんど使用されないデータは、より安価で低速のストレージメディアに移行できます。
テーブルが非常に大きくなる場合にのみ、通常、メリットは価値があります。テーブルのパーティション分割が有効になる正確な時点はアプリケーションによって異なりますが、経験則では、テーブルのサイズはデータベースサーバーの物理メモリを超える必要があります。
レンジパーティショニング
テーブルは、キーカラムまたは列のセットで定義された「範囲」に分割され、異なるパーティションに割り当てられた値の範囲が重複することはありません。たとえば、日付の範囲、または特定のビジネスオブジェクトの識別子の範囲で分割できます。