質問: webアプリを作成しています。 teratailでは、タグ別に順位表がありますが、私のアプリでも項目別に順位表を作成しようと考えています。 各項目毎に10位までの順位表を作成するにあたり、それ専用のデータベースを設けるべきか、その都度計算させた方が良いのかと考えています。 teratailでは、どういうデータベース構造になっているのかと勝手に想像してみました。 初心者なりに私が想像したのは下記の通りですが、どう思われますか?(テーブル名は勝手につけたものです) 【テーブル構成】 usersTagテーブル:フィールドは、ユーザー名、タグ名、スコアの2つ。 rankingテーブル:フィールドは、タグ名、順位、ユーザー名、スコアの4つ。予め、タグ毎に1位〜10位のレコードを登録できるようになっている。 【データ処理】 ・ユーザーが、タグを登録すると、データベースのusersTagテーブルに、レコードが追加され、ユーザー名とタグ名が登録される。スコアはデフォルトの0。 ・ユーザーが、質問を投稿したり、回答したり、ベストアンサーを付けてもらうと、 usersTagテーブルの当該ユーザーの当該タグの所に、一定のスコアを加算し、スコアを洗い替える。 そして、当該ユーザーのスコアと、rankingテーブルの当該タグの1位〜10位と比較し、rankingテーブルを洗い替える。 ・順位表を表示する時は、rankingテーブルから直接引っ張って表示するだけ(その時に順位を計算するわけではない。) 順位表を表示する都度、順位を計算している訳ではないと思うのですが、どのように想像されますか? 同じような経験がある方、このような場合、どのようなテーブル構成とデータ処理をしたか、ご教示頂ければ幸いです。よろしくお願いします。
回答: >mulberryfieldsさん 作りを想像するのって、楽しいですよね。この業界を生業にしてるので私も癖になっちゃってます。 私は、ランク自体は値として持っていない(記載いただいたところのrankingテーブルはない)に、一票です! 理由としては、2点あります。 ###### 理由1:更新のオーバーヘッドが高い ランクという値の性質上、アクションを行ってランクが上がった人だけでなく、 アクションしていない人も、追い抜かされることで、ランクの更新が必要です。 アクション×Nの更新が都度必要だと考えると、更新のオーバーヘッドが高いと考えられます。 ###### 理由2:検索はそこまで重くない 多いタグでも数千人程度しか登録していません。「Java」タグの登録者数を確認したら、 5632人でした。selectで約5000件を抽出して、順位付をするコストはそんなに高くないと考えられます。 ※OracleでいうところのWindow関数のrankを使用することを想定 ※usersTagテーブルがタグ別にパーティション化されていたら性能面は文句なし