web-dev-qa-db-ja.com

データベース設計-状態を保存するか、毎回状態を計算しますか?

リレーショナルデータベースアプリケーションと、「ユーザー」オブジェクトと「メッセージ」オブジェクトがあるとします。次に、このユーザーに未読メッセージの数を表示します。

これをアーカイブする最良の方法は何ですか?ユーザーにフィールドを導入し、ユーザーがメッセージを受け取った場合はカウントし、メッセージを読んだ場合はカウントを減らしますか?または、未読のフラグが付けられたユーザーのメッセージ数を計算するために毎回クエリを実行しますか?

最初のアプローチはより複雑でエラーが発生しやすいと思いますが、2番目のアプローチよりもパフォーマンスが向上します。

これは通常どのように行われますか、またはより良いアプローチは何ですか?

17
jan

これは通常どのように行われますか?

最善のアプローチは、追加のフィールドなしで最初に試して、パフォーマンスを測定し、それが本当に遅すぎることが判明した場合は、最適化を試みることです。これは、追加のフィールドを使用する最初のアプローチに切り替えることを意味しますが、たとえば、メッセージの結合フィールド(「未読」、「userID」)に追加のインデックスを配置するなど、他のオプションもテストすることを検討する必要があります。

14
Doc Brown

データベース理論 による教科書ソリューションは、他のデータの値に依存するデータベースに値がないことになります。これらは (推移的な依存関係 であるためです。他のフィールドに基づいて計算された値であるフィールドがあると、冗長な情報につながるため、正規化に違反します。

ただし、教科書に書かれていることと実際に最も実用的な方法は異なる場合があります。各ページビューの未読メッセージの数を数えることは、非常に負荷の高い操作になる可能性があります。 user- tableの数値をキャッシュすると、パフォーマンスが大幅に向上します。コストは、データベースに不整合が存在する可能性があることです。unread-counterを更新することを忘れずに、メッセージが削除、追加、または読み取られる可能性があります。

9
Philipp

潜在的な問題はパフォーマンスであり、まだパフォーマンスの問題はありません。ソリューション#1でこれを処理するために選択したデータベースに応じて実行できる多くのことがあります。これはすべて、ユーザーが現在の未読メッセージ数を取得する必要がある頻度に依存します。これらの選択肢の多くはアプリ側でカスタムコーディングを必要としないため、コードを変更するか、ほとんど変更せずに実装できます。アプリで成長しやすくなります。

ユーザーが接続/ログインしたら、データベースからカウントを1回取得してもそれほど問題ではありません。アプリは、メールなどのメッセージのリストを常に更新しますか?ここから未読数を取得するためにデータベースに再度アクセスする必要はありません。新しいメッセージを取得するには、とにかくデータベースにアクセスする必要があります。

IsReadにフラグを付けるためにメッセージが読み取られるたびにデータベースにアクセスしますか?フィールドは、別のフィールドの再計算なしで十分です。

ソリューション#2(フィールド内/ディスク上でカウントを維持)で、問題が発生したときにこのフィールドを定期的に再構築/再計算するルーチンが必要ですか?そして、常に問題があります。これらすべてをトランザクションでラップしますか? Userテーブルのロックが原因で受信ユーザーのUnreadCountを更新できないため、誰かが誰かにメッセージを送信するたびに失敗する可能性がありますか?または、このフィールド用に別のテーブルを作成しますか?

4
JeffO

私が行う方法は、毎回クエリを実行すること、つまり2番目のアプローチです。クエリのパフォーマンスを向上させるために、ユーザーテーブルへの外部キーとして機能する列のメッセージテーブルのインデックスを必ず追加してください。

次に、Docが言うように、このアプローチのパフォーマンスを測定すると、別の方法をとる必要があるかどうかを判断できます。

0
Jose B