10891


MySQL(InnoDB)を使って数日間の人気ランキングを作りたいと考えてます。そのテーブル構造なんですが、どのようにすると負担が少なくできるでしょうか。  
私が考えたものは、流石に１つ１つのアクセスを単一のテーブルに保存するのは良くない気がして、以下のように数日分にまとめてみようと考えました。  
商品(items)はすごくたくさんありまして、accessesをjoinするときに7日前までの日付と下記dateを比較します。もしjoin成功した場合には下記エントリのアクセス数を表示、そうでない場合にはアクセス数を0とします。  
どんなものでしょうか。もしダメでしたら改善案をいただければと思います。

[code]

    // 商品に対する日毎のアクセス数を保存
    テーブル名：accesses
    
    id primary integer auto_increment,
    item_id integer, //(商品のID)
    access integer, // (アクセス数)
    date date, // (アクセス情報の日付)
    created_at datetime, // (作成日時)
    updated_at datetime, // (更新日時)
    
    
    //itemsにおいて比較の方法(laravel 5コード)
    $item = Item::join('accesses' function($join){
        $join->on('items.id', '=', 'accesses.item_id')
            ->where('accesses.date', '>', date('Y-m-d', strtotime('-7 days')));
    })
    ....
    
[/code]


CC BY-SA 3.0
2015-06-01T22:33:06.343
10857
2015-06-02T08:30:40.980
2015-06-02T00:54:36.073
3516
9932
question
mysql laravel
1週間の人気ランキングをMySQL(InnoDB)+PHPで作りたい


最終的なランキング情報は、バッチ処理で作成するという前提で。

## 1. データベースで何とかする

`流石に１つ１つのアクセスを単一のテーブルに保存するのは良くない気がして`  
とのことですが。別に1つ1つで構いません。  
SELECT して INSERT/UPDATE するよりも楽です。

## 2. データベースで何とかしつつ、多少負荷も減らしたい。

memcachedやheapテーブルなどオンメモリ上で記録しておいて、  
バッチで定期的に計算して、集計終わった分を削除しましょう。

## 3. データベースを使わない (個人的に推奨)

そもそもアクセス都度書き込むのは、いろいろアプリ側で考慮すべき責任が多くなるので好ましくありません。  
それに、アプリケーションがアクセス記録とらなくてもwebサーバーのアクセスログに、商品IDがクエリ文字列にありませんか？
それを利用すればアプリの責任は、集計処理だけです。


CC BY-SA 3.0
2015-06-02T03:31:16.627
10867
2015-06-02T03:31:16.627
8335
10857
answer


質問のように項目ごとにをアクセス数を記録する方法だと、「該当レコードを探してきて`access`を+1」という処理になります。一方、1アクセスを1レコードで記録する場合、追加操作のみになります。表示の方を考えると、1アクセス1レコードの場合レコードをカウントしなければならないため質問の方法の方が負荷が低いでしょう。このあたりはどちらもメリットデメリットがあるので環境次第です。

ランキングを作るというのはRDBには不向きな処理で、アクセス数が膨大な場合はどちらの方法でも苦しくなってきますので、別の方法を検討する必要があります。[Redis](http://redis.io/)には「ソート済みセット型」というランキング処理の為に作られたようなデータ型があり、よく使われているようです。


CC BY-SA 3.0
2015-06-02T08:30:40.980
10891
2015-06-02T08:30:40.980
5793
10857
answer