• 締切済み

人気記事(ランキング)表示に関するDB設計や方法

DBのテーブル設計と実装について教えて頂けると嬉しいです。 登録制サイトで、記事を投稿して閲覧者がお気に入りに登録できるような仕組みを作っています。 トップページ等で「人気の記事」を表示する際、お気に入り登録数が多いものを表示させたいと思っています。 このような場合、どのようなテーブル設計や方法を取るのが良いのでしょうか? 3つ方法を思いつきますが、どれも一長一短なのかなという気がしています。 (テーブル設計の例)  「posts」テーブル  : post_id, user_id, text  「favorites」テーブル: favorites_id, user_id, post_id  「users」テーブル  : user_id, user_name (方法1)お気に入り登録数をテーブルに持たない(都度カウント処理する) トップページ表示の都度、「favorites」各記事のお気に入り登録数をカウントして(post_id で group byしてcountする)、登録の多い記事を表示させます。シンプルな方法ですが、レコード数が多い場合の負荷を心配しています。 (方法2)お気に入り登録数をテーブルに持つ お気に入り登録数を「posts」テーブル内に保持させます。  「posts」テーブル  : post_id, user_id, text, favorite_count 閲覧者がお気に入り登録した場合は「favorites」テーブルへの追加を行うと供に「posts」テーブルの「favorite_count」を更新します。トップページ表示の際は「posts」テーブルの「favorites_count」を見に行って多いものを表示させるだけなので負荷の心配は減ります。しかし、冗長な?データをテーブルに持つのは何か嫌な気がしますし、またプログラム実装が少し困難になります。 (方法3)人気の記事テーブルを別に持つ バッチ処理を1日1回等走らせ、登録数の多い記事をサーチして「人気の記事」テーブルに格納します。トップページでは、この「人気の記事」テーブルを見に行って表示させるだけになりますので負荷が減ります。しかし、リアルタイムな情報を表示できないのが残念です。 環境は、MySQL5.1、PHP5.2.17 となります。 アドバイス等頂けましたら嬉しいです。

  • MySQL
  • 回答数2
  • ありがとう数1

みんなの回答

  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.2

ご自身では、もう解決して処理を進めておられるかもしれませんが。 (それなら無視しておいてください。) レスポンス対策で、(方法1)の正規形を崩して(方法2)をとるというのは、別に問題ありません。 認識しておられないようですが、(方法3)も正規形を崩しておられます。 といいますのは、例えば、記事に問題があり緊急で削除する必要があるときに、 1つのデータを削除するために、2つのテーブルを削除する必要がでるからです。 ・・・方法2は冗長な項目を持っていますが、方法3は冗長なレコードを持っています。 ということで、 (方法2)における 「favorites」テーブル追加時に発生する「posts」テーブル更新の負荷増大 (お気に入りクリック時の負荷増大+レスポンス低下)と、 (方法3)におけるリアルタイムな情報を表示できない点および 緊急の修正あるいは、記事の修正の反映が翌日になる運用上のデメリットと この2点を天秤にかけて選ばれるのがよいかと思います。 特に記事を投稿した人が、翌日にならないとトップページのほうだけ反映されないという クレームを出さないならば、どちらでもいいと思いますし、 タブン私も(方法3)をとる可能性が大きいです。 迂回策・・・方法4) 「TopPage」テーブル  : favorite_count,post_id, user_id を作って夜間バッチ処理で上位nレコード(TOPページに表示する分)だけ作成する。 プライマリキーはfavorite_count,post_id(, user_id) ()は同一post_idがありuser_idがないとユニークにならない場合。 表示は、「TopPage」テーブルと「posts」テーブルをjoinする といった方法もあります。 アクセス数が多いとjoinする分DBサーバの負荷が高くなるので これもどれくらいのアクセスを想定するかとDBサーバの能力しだいで最良か最悪かが変わります。 (TOPページなので当然アクセス数は多いはずですし。)

回答No.1

方法その3のリアルタイム性については、人気記事の集計処理を Windows であればタスクスケジューラ、 Linux などであれば cron などで5分から60分程度の間隔で起動し(ようするに自動バッチ処理)人気の記事テーブルを更新すれば一般的な利用者のニーズは満たせるかと思います。 また、人気の記事テーブル(データベース)にデータを置くよりも共有メモリ領域やテキストファイルに人気の記事のデータを置く(キャッシュしておく)方がDBにアクセスするよりも処理負荷が低く、処理速度が高速になることが考えられます。ただ、実装の手間がやや増えると思いますので参考に留める程度にしていただければいいかと思います。 とりあえず、タスクスケジューラもしくは cron などで人気記事の集計処理を実行する方法を検討してみてはどうでしょうか? なお、方法その1は violinmaker さんの懸念の通り会員・記事数が増えたときに問題になることが考えられます。逆に、会員数が小数固定であれば、実装が簡潔になるのでいいかと思います。 方法その2は、データベース設計の基本を守るべきですので止めるべきと思います。

violinmaker
質問者

お礼

ありがとうございます。 こういった処理は初めてなので、頂いたコメントが参考になります。 確かに3番目の方法が負荷や将来性の面から良さそうに思います。(一般的にとられている手法なのでしょうか?) 実は方法2に傾きつつありましたが、やはりデータベース設計からすると好ましくないということですよね。 方法3のバッチ処理で人気記事の集計を行う形で検討してみたいと思います。

関連するQ&A

  • Cakephpでランキング機能の作成方法について。

    Cakephpでランキング機能の作成方法について。 Cakephpで、お気に入り数順のランキング機能を作りたいと考えています。 以下のような構造でランキングを表示させたいのですが、 やり方が分からず困っています。 ■システム概要 コーヒーの紹介サイトです。 様々なコーヒーが登録されており、ユーザーは任意のコーヒーをお気に入り登録できます。 Coffeeテーブル id , name Userテーブル id , name Favoriteテーブル id , coffee_id , user_id 現在、ランキングを表示させたいページであるindex.ctpには、$this->Coffee->find();でCoffeeの情報を表示させています。 アソシエーションでUserテーブル、Favoriteテーブルの情報も取れていますが、これをお気に入り数順にソートするやり方がわかりません。宜しくお願いします。

    • ベストアンサー
    • PHP
  • CakePHPでのコメント数表示について

    CakePHPを使って簡単な掲示板を開発しているのですが、トップページに 各トピックについたコメント数を表示させる方法で壁にぶち当たってしまっております。 データの取り出し方及び表示方法について教えて頂ければと思います。 DB構造(モデル)としては、 ==================================== ■掲示板(post.php) テーブル:posts id title contents ■コメント(comment.php) テーブル:comments id post_id comment ==================================== となっており、postsにhasMany、commentsにbelongsToで アソシエーションを貼ってあります。 コントローラー(posts_controller.php)では、 ==================================== $data = $this->Post->find('all',array('order' => array('Post.id' => 'desc'))); $this->set('data',$data); ==================================== という処理を行い、 ビュー(/posts/index.ctp)では、 ==================================== foreach($data as $val){ echo "<tr>"; echo "<td><a href='{$val['Post']['id']}'>$val['Post']['title']</a></td>"; echo "</tr>"; } ==================================== としています。 これで、トップページに行くと掲示板トピックスのタイトルの 一覧は表示できるのですが、その横についたコメント数を表示 させたいのです。 例)掲示板のタイトルです(13) 上記のように(○)とさせたいのです。 コントローラーの所でallではなくcountにすることで件数を取りだす ことができる所まではできるのですが、 $cnt = $this->Post->find('count',array('order' => array('Post.id' => 'desc'))); などとやっても本来取り出したいcommentsではなくpostsの件数を取りだす ことになってしまっています。 また、hasManyを利用すると、 Array( [0] => Array( [post] => Array( [id] => 1 [title] => 掲示板のタイトルです [contents] => 掲示板の内容です [comment] => Array( [0] => Array( [id] => 1 [post_id] => 1 [comment] => コメント1です。 [1] => Array( [id] => 2 [post_id] => 1 [comment] => コメント2です。 ・ ・ ・ となる為、ビューでの表示のさせ方にも困っております。

    • ベストアンサー
    • PHP
  • DB設計について

    ユーザー情報などで、チェックボックスで複数選択してもらった項目を DBへ登録する場合どのように、テーブルを作るのが良いのでしょうか? 例えば、一つのフィールドに、選択してもらった項目を user_id hoby 1    'サッカー,野球,バスケ' などと入れるのがいいのか、 別の、テーブルを作って、 user_id hoby 1    サッカー 1    野球 1    バスケ この方がよいのか、どちらがよいのでしょうか、よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • WordPressの任意のカテゴリを記事をトップページへ表示させる方法+α

    ちょっと壁にぶつかりまして、質問させて頂きます。 「おすすめ」というカテゴリを作成し、それに属する記事たちを トップページに表示させる、という話なのですが、 <h3 id="h-recommend">おすすめの記事</h3> <?php $posts = get_posts('category_name=recommend'); foreach($posts as $post) : setup_postdata($post); ?> <h4><?php the_title(); ?></h4> <p>記事本文</p> <?php endforeach; ?> と記述しました。試しに、記事を三つばかり 「おすすめ」カテゴリに設定して投稿したら、 <h3>おすすめの記事一覧</h3> <h4>記事その(1)</h4> <p>記事その(1)の本文</p> <h4>記事その(2)</h4> <p>記事その(2)の本文</p> <h4>記事その(3)</h4> <p>記事その(3)の本文</p> という風になり、とりあえずの成功はしました。 この場合、<h4>たちに関しては、記事が0の時は当然何も表示されない のですが、 <h3>だけ表示されている状態が不自然です。 今回、記事を投稿して初めて<h3>も含む記事全てが表示さる ようにしたいと思っています。 但し、この時<h3>は繰り返しをしません。 「おすすめ」カテゴリに記事を投稿して初めて全てが発動する、 と言った感じにしたいです。 どのような記述方法を取ればよろしいでしょうか? どなたかご教授頂ければ、非常に助かります。よろしくお願い致します。

  • 動的な(?)値のつくりかた

    user_table --------------- user_id user_name posts --------------- entry_table --------------- entry_id user_id document このようなテーブルがあったとして、 user_tableのpostsの値を entry_tableのなかのuser_idが一致するレコードの数と同じにするには どのような方法がありますか? 文章がおかしいかもしれませんが、よろしくお願いします。

    • ベストアンサー
    • MySQL
  • 自作PHPブログでの記事を5件ずつ表示する方法に

    自作PHPブログでの記事を5件ずつ表示する方法について PHPで自作のブログをサイト等を参考に制作しているのですが、 最新の記事5件ずつ表示させたい場合はどのような記述をすれば良いのでしょうか? 「前ページ」と「次ページ」的なリンクを貼りたいと思っております。 一番最古の記事のページまで行くと「前ページ」リンクも消えるようにしたいのです。 pager等を検索したのですが、いまいち自分の物に組み込むとなるといまいちよくわからなくなります。 LIMITで5件表示まではわかったのですが、「次へ」で6~10件表示の仕方がわかりませんでした。 どのような記述が良いでしょうか、よろしくお願いします。 <?php $pdo = new PDO("mysql:dbname=blog", "root"); $st = $pdo->query("SELECT * FROM post ORDER BY no DESC LIMIT 5"); $posts = $st->fetchAll(); for ($i = 0; $i < count($posts); $i++) { $st = $pdo->query("SELECT * FROM comment WHERE post_no={$posts[$i]['no']} ORDER BY no DESC"); $posts[$i]['comments'] = $st->fetchAll(); } require 't_index.php'; ?> t_index.phpで表示のプログラムを書いています。

    • 締切済み
    • PHP
  • WPのカテゴリのビュー数を表示させたい

    WordPress でプラグインを使用しないで記事のビュー数を表示させるコードは結構あったので見つけることができました。 -------------- //PV数をカスタムフィールドに保存 function wpb_set_post_views($postID) { $count_key = 'wpb_post_views_count'; $count = get_post_meta($postID, $count_key, true); if($count==''){ $count = 0; delete_post_meta($postID, $count_key); add_post_meta($postID, $count_key, '0'); }else{ $count++; update_post_meta($postID, $count_key, $count); } } remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0); //投稿が閲覧されるたびにカスタムフィールドの値が更新 function wpb_track_post_views ($post_id) { if ( !is_single() ) return; if ( empty ( $post_id) ) { global $post; $post_id = $post->ID; } wpb_set_post_views($post_id); } add_action( 'wp_head', 'wpb_track_post_views'); //PV数取得 function wpb_get_post_views($postID){ $count_key = 'wpb_post_views_count'; $count = get_post_meta($postID, $count_key, true); if($count==''){ delete_post_meta($postID, $count_key); add_post_meta($postID, $count_key, '0'); return "0 View"; } return $count.' Views'; } --------------------- これを記事ではなくて、カテゴリでランキングを付けたい場合はどうすればいいのかがわかりません。 1)どのカテゴリが一番人気があるか、記事でなくカテゴリでランキングをつけたいです。 2)また、ビュー数を毎月調べたいので、1か月毎に初期化(0からカウント)するにはどうすればいいのかも教えて欲しいです。 3)もし、プラグインでカテゴリのビュー数を表示できるのがあったら、該当のプラグインを教えてほしいです。 よろしくお願い致します。

    • ベストアンサー
    • PHP
  • 5つずつ15件の記事を分割して表示したい

    <!--ループ1--> <?php $wp_query = new WP_Query(); $args = array( 'post_type' => "post", //投稿タイプ設定 'posts_per_page' => 2, // 表示する投稿数(-1を指定すると全投稿を表示) ); $wp_query->query($my_posts); if ($wp_query->have_posts()) : $i = 0; $i <= 10; while ($wp_query->have_posts()) : $wp_query->the_post(); ?> <?php /**** ▼1件分の投稿内容HTML ****/ ?> <?php $i++; ?> <?php if ($i >= 3) break; ?> <?php endwhile; ?> <?php endif; ?> <!--//ループ1--> <!--ループ2--> <?php $wp_query = new WP_Query(); $args = array( 'post_type' => "post", //投稿タイプ設定 'posts_per_page' => 2, // 表示する投稿数(-1を指定すると全投稿を表示) ); $wp_query->query($my_posts); while ($wp_query->have_posts()) : $i<=7;//iが7より小さい時は処理を繰り返す。 if ($wp_query->have_posts()) : $i>4; //iが4より大きい時は、実施する。 continue; // 以降の処理をスキップし、次の回(条件2)に移る $wp_query->the_post(); ?> <?php /**** ▼1件分の投稿内容HTML ****/ ?> <?php $i++; ?> <?php if ($i >= 3) break; ?> <?php endif; ?> <?php endwhile; ?> <!--//ループ2--> $wp_query->query($my_posts);で投稿ページの情報を吸い取り、そこからタイトルや画像やコメントを取得しているようですが。 $my_postsは先頭に戻る特性があって、それを読み飛ばす処理が必要となっているようです。 そこで $i>4;//iが3より大きい時は、while文を強制終了する $wp_query->the_post(); continue; // 以降の処理をスキップし、次の回(条件2)に移る?>として 読み飛ばす処理を実装したつもりが記事が表示されません。原因は何が考えられるでしょうか?

    • ベストアンサー
    • PHP
  • 人気ブログランキングについて。

    最近seesaaブログに登録した初心者です。 人気ブログランキングに登録したのはいいのですが、ブログからアクセスする方法がわからないし、うまくメインページにブログランキングのバナーを表示させられず困っています。 今困っている点をまとめるとseesaaブログについて、 1.人気ブログランキングのバナーの貼り方(トップへの)がわからない。 2.そのバナーからランキングのページにリンクさせたい。 この方法がわかる方、よろしくお願いします。

  • MovableTypeに人気記事ランキングを設置

    MTバージョン5.2.2を使用しています。 運用中のブログに人気記事アクセスランキングを設置したいのですが、 うまくいかないので質問です。 今まで導入を試みたのは、 ・AccessCounter 1.04 http://www.homepagemaker.biz/2008/11/access-counter-1.html 管理画面のブログ記事リストページにアクセスすると、 「リストプロパティの初期化に失敗しました: accessed_countというカラムは見つかりません。 」 とメッセージが出て一覧が表示できなくなります。 5.2に対応との記載はないのでバージョンの問題かもしれません。 ・AccessRankingGA 0.5 https://github.com/coolniikou/mt-plugin-AccessRankingGA jsonファイルの生成を確認しましたが内容がページに表示されませんでした。 上記エラーへの対処法、もしくは別のランキング表示方法があれば教えてください。 現状のソース等必要であれば追記します。 どうぞよろしくお願いします。