• 締切済み

分単位でログ集計するためカウントする方法

アクセスログの分析のため月ごとで、データをlog_siteというテーブルに入れ込んでいます。(データ量は約4500万件) ※実際はもっと項目(リクエストURL、HTTPステータス、UAなど)がありますが、 ここでは省略しています。 +----+-----------------+--------------------+----------+----+------+ + No | IP | DATETIME | YYYYMMDD | HH | HHMM | +----+-----------------+--------------------+----------+----+------+ + 1 | XXX.XXX.XXX.XXX | 2012-11-14 18:50:11| 20121114 | 18 | 1850 | + 2 | XXX.XXX.XXX.XXX | 2012-11-14 11:44:04| 20121114 | 11 | 1144 | + 3 | XXX.XXX.XXX.XXX | 2012-11-14 17:16:06| 20121114 | 17 | 1716 | + 4 | XXX.XXX.XXX.XXX | 2012-11-03 16:47:01| 20121103 | 16 | 1647 | + 5 | XXX.XXX.XXX.XXX | 2012-11-05 19:35:18| 20121105 | 19 | 1935 | + 6 | XXX.XXX.XXX.XXX | 2012-11-03 16:52:39| 20121103 | 16 | 1652 | + 7 | XXX.XXX.XXX.XXX | 2012-11-04 15:19:40| 20121104 | 15 | 1519 | + 8 | XXX.XXX.XXX.XXX | 2012-11-12 12:34:58| 20121112 | 12 | 1234 | + 9 | XXX.XXX.XXX.XXX | 2012-11-09 09:50:53| 20121109 | 09 | 0950 | + 10 | XXX.XXX.XXX.XXX | 2012-11-09 13:08:53| 20121109 | 13 | 1308 | + 11 | XXX.XXX.XXX.XXX | 2012-11-08 06:57:31| 20121108 | 06 | 0657 | + 12 | XXX.XXX.XXX.XXX | 2012-11-13 11:12:14| 20121113 | 11 | 1112 | + 13 | XXX.XXX.XXX.XXX | 2012-11-05 10:22:42| 20121105 | 10 | 1022 | +----+-----------------+--------------------+----------+----+------+ 各項目は以下のように定義しています。 `No` int(11) NOT NULL AUTO_INCREMENT, `IP` varchar(15) DEFAULT NULL, `DATETIME` datetime DEFAULT NULL, `YYYYMMDD` varchar(8) DEFAULT NULL, `HH` varchar(2) DEFAULT NULL, `HHMM` varchar(4) DEFAULT NULL, やりたいこととしては、1分または1時間単位でアクセスを集計しグラフを書こうとしています。 グラフに対しては、43,56,35,・・,5といった状態で渡せばグラフを書いてくれるのですが、 そのデータを取り出すため以下のようなSQLを書いて、各1分単位でそのカウントをして見ました。 select HHMM, count(IP) from log_site where YYYYMMDD='20121101'and ( (HHMM='0000')or(HHMM='0001')or(HHMM='0002')・・・・(HHMM='2359') )group by HHMM; +------+-------+ + HHMM | count | +------+-------+ + 0001 | 43 | + 0002 | 56 | + 0003 | 35 | (----省略----) + 2359 | 5 | +------+-------+ アクセス時間については、DATETIMEの項目にデータを入れているのですが 1分ずつ、1時間ずつ集計するのに日時や秒の情報が邪魔だったので YYYYMMDD、HH、HHMMといった内容で情報を持たせています。 実行した結果、取得できるのに300-400秒必要なのですが、 1日を取得するだけで、5-7分要するのは、なんとかならないでしょうか? 最低でも3日、最高で7日間ぐらいのデータは取得したいと考えているため、 この時間はかかりすぎなのです。 やはりログデータ量が約4500万件あるという多さから予め日ごとで集計された 数字を別テーブルに持たせることを考えていたのですが、 引っ掛けたいリクエストURLや、HTTPステータス、UAなど他の項目でも アクセス傾向が知りたいため、予め日ごとで集計された結果を別テーブルに持つ ということは出来ないので、予め集計された結果を持っておく訳にも行かず困っています。 もし今の状況でどのようなSQLだったら、データをスムースに取得できるのでしょうか? またスムーズにデータを取得するためにデータ構造の見直しが必要としたら どのように変えて、かつどのようにsqlを組んで取得すればよいのでしょうか? (仮に、日ごとでテーブルを作った場合は1日あたり150万程度になりますが 日をまたぐ場合は、どのようなSQLになるのでしょうか?) もっといい方法があれば教えていただければと思います。 よろしくお願いいたします。

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

みんなの回答

  • ki073
  • ベストアンサー率77% (491/634)
回答No.2

まったくSQLを使っていませんが、logがそのまま残っているのなら、このような方法があります。 cut -c1-19 <log.log|uniq -c >result.txt 日付時刻部分を切り出してuniq -cで行数を数えるものです。 2日分300万件の疑似ログデータを作成して8秒で集計できました。 除外したいデータが有る場合にはgrepなどを入れる必要があるのでもう少し時間がかかりますが。 ご参考に

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

とりあえずインデックスは? あとデータの持ち方と集計方法を工夫したほうが CREATE TABLE `log_site`( `No` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `IP` VARCHAR(15), `DATETIME` DATETIME, `YYYYMMDD` DATE, `HH` TIME, `HHMM` TIME); ALTER TABLE `log_site` ADD INDEX(`YYYYMMDD`,`HHMM`); INSERT INTO `log_site`(`IP`,`DATETIME`) VALUES( 'XXX.XXX.XXX.XXX','2012-11-14 18:50:11'),( 'XXX.XXX.XXX.XXX','2012-11-14 11:44:04'),( 'XXX.XXX.XXX.XXX','2012-11-14 17:16:06'),( 'XXX.XXX.XXX.XXX','2012-11-03 16:47:01'),( 'XXX.XXX.XXX.XXX','2012-11-05 19:35:18'),( 'XXX.XXX.XXX.XXX','2012-11-03 16:52:39'),( 'XXX.XXX.XXX.XXX','2012-11-04 15:19:40'),( 'XXX.XXX.XXX.XXX','2012-11-12 12:34:58'),( 'XXX.XXX.XXX.XXX','2012-11-09 09:50:53'),( 'XXX.XXX.XXX.XXX','2012-11-09 13:08:53'),( 'XXX.XXX.XXX.XXX','2012-11-08 06:57:31'),( 'XXX.XXX.XXX.XXX','2012-11-13 11:12:14'),( 'XXX.XXX.XXX.XXX','2012-11-05 10:22:42'); UPDATE `log_site` SET `YYYYMMDD`=DATE(`DATETIME`) ,`HH`=CONCAT(HOUR(`DATETIME`),':00:00') ,`HHMM`=CONCAT(HOUR(`DATETIME`),':',MINUTE(`DATETIME`),':00') WHERE `YYYYMMDD` IS NULL; SELECT `HHMM`, COUNT(*) AS COUNT FROM `log_site` WHERE `YYYYMMDD`='2012-11-03' GROUP BY `HHMM`;

関連するQ&A

  • SQLの時間データを15分単位で集計できますか?

    SQLで質問させてください。 現在、datetime型の項目があるのですが、これを15分単位で集計したいのです。具体的には以下のようなテーブルとなっています。 時間        値 ―――――――――――――――― 2009/1/1 15:02:00 1 2009/1/1 15:04:00 1 2009/1/1 15:16:00 1 2009/1/1 15:31:00 1 2009/1/1 15:48:00 1 2009/1/1 16:04:00 1 これを次のような形に集計できないものでしょうか? 年月   時間    数 ―――――――――――――――― 2009/1/1 15:00   2 2009/1/1 15:15 1 2009/1/1 15:30 1 2009/1/1 15:45 1 2009/1/1 16:00 1 何かアイデアがございましたら、よろしくお願いします。

  • SQLServerで・・・

    SQLを発行してデータ取得したいと考えています。 テーブルの構成は 名前 varchar(512) アクセス日付 datetime(8) 住所 varchar(512) の3つの項目です。 ここで日にちごとにアクセスした人をカウントしたいと考えています。 アクセス日付には 2002-12-24 19:10:20:17.00 2002-12-25 15:11:01:21.00 2002-12-25 09:25:20:08.00 2002-12-26 21:10:20:17.00 というフォーマット(デフォルト?)で格納されています。 この場合、2002年12月25日にアクセスした人をカウントする SQLを書きたいのですが、どのようにすればいいのでしょうか? select 名前, アクセス日付, 住所 from テーブル where アクセス日付 = '???'; 実際にSQLを発行できる環境があればいいのですが、 宜しくお願いいたします。

  • SQLで、アクセス集計について困っています。

    アクセス集計について困っています。 mysql> desc access_log; +------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | user_id | varchar(50) | YES | | NULL | | | ip | varchar(15) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+-------------+------+-----+---------+----------------+ 5 rows in set (0.02 sec) mysql> select * from access_log; +----+---------+-----------+---------------------+---------------------+ | id | user_id | ip | created_at | updated_at | +----+---------+-----------+---------------------+---------------------+ | 1 | admin | 127.0.0.1 | 2010-11-13 21:56:54 | 2010-11-13 23:07:27 | | 2 | admin | 127.0.0.1 | 2010-11-13 21:56:54 | 2010-11-13 23:07:27 | | 3 | admin | 127.0.0.1 | 2010-11-14 21:56:54 | 2010-11-13 23:07:27 | | 4 | admin | 127.0.0.1 | 2010-11-14 21:56:54 | 2010-11-13 23:07:27 | | 5 | admin | 127.0.0.1 | 2010-11-15 21:56:54 | 2010-11-13 23:07:27 | +----+---------+-----------+---------------------+---------------------+ 5 rows in set (0.00 sec) 上記のように定義したテーブルがあります。 SELECT a.id, a.user_id, COUNT(*), DATE(a.created_at) AS date FROM access_log a WHERE (a.user_id = 'admin' AND a.created_at > '2010-11-01 00:00:00' AND a.created_at < '2010-11-29 23:59:59') GROUP BY date ORDER BY a.created_at; のようにして日別のアクセス数の集計をしています。 ここから、同じ日の同一IPのアクセスは1アクセスとして計算したいのですが、 どのようにSQLを書けばよいでしょうか? よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • プライマリーキーの昇順でソートにならないのは?

    現在PHPで開発しています。 テーブル構造は下記の通りです。 CREATE TABLE `timetable` ( `ID` int(3) unsigned NOT NULL auto_increment, `gettime` int(10) unsigned default NULL, `code` varchar(20) default '0', //英数字が入る `time` varchar(50) default '0', //日本語が入る `timeh` datetime default NULL, PRIMARY KEY (`ID`), KEY `gettime` (`gettime`) ) ENGINE=MyISAM DEFAULT CHARSET=ujis これでふつうに select ID,gettime,code from timetable where code='xxx' とすると ------------ 16435 5 xxx 16434 4 xxx 16433 3 xxx 16432 2 xxx 16431 1 xxx と取得されてしまい、IDの昇順になってくれません。 select * でも同様です。LIFO型になっているように見られます。 ご助言いただきたいのは ・MySQLの場合、こうなることはあるのか、原因は何か ・対応としてはorder by をつける以外にないのか  (テーブルの構造、設定を変えることで対応可能か) です。お忙しいと存じますが宜しくお願い致します。

    • ベストアンサー
    • MySQL
  • どうしてもこのクエリーがミスになる

    Webmin上からテーブルを作成しようとしたら、以下のようにエラーになりました。 テーブルを作成できませんでした : SQL create table `page` (`page_id` mediumint(10000) not null,`title` varchar(100) not null,`descrption` varchar(500) not null,`keywords` varchar(100) not null,`parent_id` mediumint(10000) not null,`page_seq` int(100) not null,`createdate` datetime not null default 'now()',`modifydate` datetime not null default 'now()') が失敗しました: Display width out of range for column 'page_id' (max = 255) page_id はmediumint(10000)にしてるのに、なぜ「column 'page_id' (max = 255)」と言われてしまうのか不思議です。 どなたかおわかりのかたいらっしゃいましたら、お教えいただければ幸いです

    • ベストアンサー
    • MySQL
  • アクセスログテーブルの構造について

    このジャンルでお願いします。 よくアクセスログの解析を無料で(リンクを貼ったりして)行ってくれるサービスがありますが、 そのデータベースの構造というかテーブルの構造はどのようになっているのでしょうか? 例えば、膨大なレコード数になると思うので それを利用するユーザー毎にテーブルを分けるとかするのでしょうか? あるいはユーザー毎、年毎、月毎、日毎、に分けるとか? 本来ならテーブルを分割したりするのは違うんじゃないかなぁと思ったりするのですが、 なので次のように、 CREATE TABLE `accesslog` ( `id` int NOT NULL auto_increment, `user_id` varchar(16), `created` datetime, `ip` varchar(64), FOREIGN KEY(`user_id`) REFERENCES `user`(`id`) ); ユーザーも全ての期間のデータも1つのテーブルで管理するのが普通だとは思うのですが、 アクセスログだけは利用するユーザー数にもよりますがやはり膨大になりますよね? そうすると1つのテーブルだと無理があると思うのです。 あるいは単にテキストファイルとして保存する方法もあるのかな?と思うのですが、 やはりなにかとSQLで操作したいのでMySQLなどのテーブルの設計が知りたいです。

  • MySQL insert文に関するエラーについて

    ○質問の主旨 MySQLのデータベースにテーブルを作ってinsert文で データを追加しようとするとシンタックスエラーが出ます。 SQL文が間違っているのかと思いGoogle検索や本で調べたりしましたが、 なぜ文法エラーが発生するのか分かりません。 エラーと対処方法をご存知の方がいらっしゃいましたらご教示願います。 ○質問の補足 // usersテーブル create table users ( id int not null auto_increment primary key, created datetime not null, modified datetime not null, username varchar(255), password varchar(40) ); desc users; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | created | datetime | NO | | NULL | | | modified | datetime | NO | | NULL | | | username | varchar(255) | YES | | NULL | | | password | varchar(40) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ insert into users (created, modified, username, password) values (now(), now(), 'test1', 'test1'), (now(), now(), 'test2', 'test2') ); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 3

    • ベストアンサー
    • MySQL
  • joomlaのインストールについて

    joomlaのインストールでmysqlのデータベース情報を入力し次へを押すと下記のメッセージがでます。 (インストール画面では無く、白いページに文字だけが表示されています) 接続は出来ていると思うのですが、どうしたらインストールを続けることが出来るのでしょうか? 【環境】 FreeBSD7 php5 mysql6 【メッセージ】 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TYPE=MyISAM' at line 29 SQL=CREATE TABLE `jos_banner` ( `bid` int(11) NOT NULL auto_increment, `cid` int(11) NOT NULL default '0', `type` varchar(90) NOT NULL default 'banner', `name` TEXT NOT NULL default '', `alias` varchar(255) NOT NULL default '', `imptotal` int(11) NOT NULL default '0', `impmade` int(11) NOT NULL default '0', `clicks` int(11) NOT NULL default '0', `imageurl` varchar(100) NOT NULL default '', `clickurl` varchar(200) NOT NULL default '', `date` datetime default NULL, `showBanner` tinyint(1) NOT NULL default '0', `checked_out` tinyint(1) NOT NULL default '0', `checked_out_time` datetime NOT NULL default '0000-00-00 00:00:00', `editor` varchar(150) default NULL, `custombannercode` text, `catid` INTEGER UNSIGNED NOT NULL DEFAULT 0, `description` TEXT NOT NULL DEFAULT '', `sticky` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, `ordering` INTEGER NOT NULL DEFAULT 0, `publish_up` datetime NOT NULL default '0000-00-00 00:00:00', `publish_down` datetime NOT NULL default '0000-00-00 00:00:00', `tags` TEXT NOT NULL DEFAULT '', `params` TEXT NOT NULL DEFAULT '', PRIMARY KEY (`bid`), KEY `viewbanner` (`showBanner`), INDEX `idx_banner_catid`(`catid`) ) TYPE=MyISAM

    • 締切済み
    • PHP
  • 時間の抽出条件

    業務で開発中、どうしてもわからなかったので質問させていただきます。 あるテーブルから「データを抽出する日の14時までにできたデータのみを抽出する」というSQLですが、 データを抽出する日→SYSDATEでYYYYMMDDまでを取得する考えです。 このあとの14:00:00という条件をつけるSQLの書き方がわかりません。 このような書き方ではだめでしょうか? SELECT * FROM T_TEST WHERE DATAYMD < TO_CHAR(SYSDATE '14:00:00','YYYYMMDD HH24:MI:SS'); DATAYMDはCHAR型で8バイトで入っています。 よろしくお願いいたします。

  • 件数をカウントして日付でソートするSQL

    こんなテーブルがあったとして、 テーブル名:shohin ------------------- type:文字列 create_date:日付 こんなデータになっていたとして type| create_date ----+----------- abc | 2004/02/01 abc | 2004/02/02 abc | 2004/02/03 hhh | 2004/01/30 xxx | 2004/01/12 xxx | 2004/01/13 xxx | 2004/01/14 xxx | 2004/01/15 xyz | 2004/01/01 xyz | 2004/01/05 このようなデータを出力したいのですが… (typeで集計して、create_dateの一番新しい日付でソート) type | count | create_date -----+-------+----------- abc | 3 | 2004/02/04 -----+-------+----------- hhh | 1 | 2004/01/30 -----+-------+----------- xxx | 4 | 2004/01/15 -----+-------+----------- xyz | 2 | 2004/01/05 これを一発で書くSQLって可能でしょうか? 副問い合わせを使えば出来るような気がするのですが、Group By した結果からさらに最新の日付を取得してソートというのがどうも上手く書けませんでした。 お分りになる方がいらっしゃいましたら、ぜひともご教示願います。