人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHPとMySQLでアクセスカウンター(ログ履歴)のようなものを作っています。

例えば6月15日にアクセスがあればテーブルに追加してcount(フィールド名)を1とし、dateに2007-06-15を入れて保存。更新されればcountに+1され2として更新されます。次の日にアクセスがあれば、新規にテーブルに追加される、と言ったイメージです。

現在は以下のようにしています。(要約しています)
$today = date("Y-n-d"); //今日の日付を取得
$sql = "select date from counter where date='$today'";
$res = mysql_query($conn,$sql);

if(mysql_num_rows($res)=="0"){ // 登録されているか調べる
// テーブルに新規登録するコード
}else{
// テーブルを更新するコード
}

しかし、上記では効率が悪いと思い、出来るだけ簡略化したソースで新規か更新か判別出来ればと思っています。新規登録・更新を繰り返し行うと負荷もかかるそうですし。

文面だけではわかりづらいかもしれませんが、どのようなソースの書き方が良いと思われるでしょうか?

具体的なソースコードは結構ですので、構造・考え方を教えていただければと思います。

●質問者: kt26
●カテゴリ:ウェブ制作
✍キーワード:2007-06-15 6月15日 MySQL PHP SELECT
○ 状態 :終了
└ 回答数 : 6/6件

▽最新の回答へ

1 ● t_shiono
●25ポイント

テーブルを2つに分けるのはどうですか?

「全てのアクセスの履歴を格納するテーブルA」と「日付ごとのアクセス数のテーブルB」を用意しておき、日付が変わった時点で、Aを集計し、その結果を元にBを更新する。

文面からは読み取れなかったのですが、行いたいことが、リアルタイムにデータを表示するよりは、後から統計的に使いたいというように思われたので。

テーブルAのサイズは大きくなりますが、不要であればBにデータを追加した時点で過去のものを消してしまってもよいと思います。


あとは、用途次第でしょうか。

◎質問者からの返答

回答ありがとうございます。私もそれは考えていて、質問には書いていませんが、cronで処理して日付が変わったら、履歴を格納するテーブルに集計するようにしています。

ただ、もっと効率化出来ないものか?sqlの書き方で何とか出来ないものか?っと思って質問しました。

これが1コンテンツだけならいいですが、アクセス集計、ポイント履歴、ランキング履歴…っと増えていくと、倍々でテーブル数も増えていきますし‥。


2 ● t_shiono
●25ポイント

では、空データを常に用意しておくのはどうですか?

毎日23:59:59にでも、アクセス数0で翌日の分のデータを作成しておくと、アクセス時には、必ずデータは存在するので、updateを行うだけでよいです。

データの確認とデータの更新をアクセス時に行う以上、提示しているものよりは効率化は難しいので、データの確認を不要にする必要があると思います。

その方法としては、

常にデータを用意しておく(今回の答え)

または、

確認を不要にする(先ほどの答え)

となってしまうのかと。

いかがでしょうか?

◎質問者からの返答

なるほど。その考えはありませんでした。先に用意しておけばupdateですみますからね。

いろんな角度から回答ありがとうございます。参考にします。


3 ● mass3
●15ポイント

掲載してあるプログラムだと、N件のアクセスがあったとき、2N回のSQLの実行がされます。内訳は以下のとおりです。

select文の実行 N回

insert文の実行 1回

update文の実行 N-1回

データベースの初心者が書いたコードはこんな風になっていることが多いです。

select文をやめてしまって、いきなりupdate文を実行、そしてupdateの影響を受けた行数が0行だったら、insert文を実行するプログラムに変更したとき、同じくN件のアクセスがあったときSQLの実行回数はN+1回ですみます。

update文の実行 N回

insert文の実行 1回

◎質問者からの返答

なるほど。先に存在するかどうか調べるのではなく、”存在していない場合”の処理(登録)にするという事ですね。

こちらも参考にさせていただきます。


4 ● chuken_kenkou
●30ポイント

sqlの書き方で何とか出来ないものか?っと思って

表の設計等でなく、SQLの書き方に絞ると。。。

1.selectでの存在有無のチェックをやめる

(1)updateの操作行数を利用

update counter
 set count=count+1
 where date=curdate()

updateで影響を受けた行数を得る方法があると思うので、その行数が0なら、insertする。

(2)MySQL 4.1サポートのinsert文での「ON DUPLICATE KEY UPDATE」を使う。

キー(今回の場合は、日付)重複の有無で、重複なしの場合は通常のinsert、重複の場合は「ON DUPLICATE KEY UPDATE」で指定された列の更新を行なってくれる。

MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 6.4.3 INSERT 構文

◎質問者からの返答

(2)の方、初耳でしたので、凄く勉強になりました。早速実験してみます。ありがとうございました。


※後で気づいたらMySQL4.1系じゃないと駄目なんですね。。私の利用しているサーバは4.0.x系だったので、他の方法を考えます。


5 ● b-wind
●15ポイント

その方法だと、トランザクションを使ってもテーブルロックでもかけない限り同時アクセス時に取りこぼしが発生しますね。


一般にアクセスログ(アクセス解析)用のデータは蓄積はアクセスごとなので頻度は高いですが、参照(統計データ)は確認したい時に見るだけなので使用頻度は低いです。


このため、1アクセスごとに1レコード(既存レコードの更新ではなく全て新規)記録していく形を推奨します。

その方がリファラやアクセス元など残せる情報も多いですし。


アクセス記録は、

INSERT INTO table ( date ) VALUES ( CURRENT_DATE );

集計処理は

SELECT count(*), date FROM table GROUP BY date ORDER by date;

とでもすればよいと思います。

◎質問者からの返答

ありがとうございます。参考にさせていただきます。


1-5件表示/6件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ