工作笔记

本文介绍了一个复杂的MySQL存储过程,用于统计特定时间段内高点击量文章的独立IP访问量,并探讨了其执行效率的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用户表:user
+-----------+------------------+------+-----+---------------------+----------------+ 
¦   Field           ¦   Type                           ¦   Null   ¦   Key   ¦   Default         ¦   Extra                      ¦ 
+-----------+------------------+------+-----+---------------------+----------------+ 
¦   ID                 ¦   int(10)   unsigned  ¦   NO     ¦   PRI   ¦   NULL           ¦   auto_increment   ¦ 
¦   userid         ¦   
varchar(30)              ¦   NO     ¦             ¦                        ¦                                   ¦ 
+-----------+------------------+------+-----+---------------------+----------------+ 

ID是用户id,userid是用户名


文章表:archives

+-------------+------------------+------+-----+---------+----------------+ 
¦   Field               ¦   Type                           ¦   Null      ¦   Key   ¦   Default   ¦   Extra                     ¦ 
+-------------+------------------+------+-----+---------+----------------+ 
¦   ID                     ¦   int(11)   unsigned   ¦   NO       ¦   PRI   ¦   NULL         ¦   auto_increment   ¦ 
¦   click                 ¦   
int(11)   unsigned   ¦   NO       ¦            ¦   0                  ¦                                 ¦ 
¦   title                   ¦   
varchar(80)              ¦   NO       ¦   MUL ¦                       ¦                                 ¦ 
¦   pubdate          ¦   
int(11)                       ¦   NO       ¦             ¦   0                  ¦                                 ¦ 
¦   adminID         ¦   
int(11)                       ¦   NO       ¦             ¦   0                ¦                                 ¦ 
¦   maxpage        ¦   
int(4)                         ¦   YES      ¦             ¦   1               ¦                                 ¦ 
+-------------+------------------+------+-----+---------+----------------+ 

ID是文章的id,自增,click是总点击量,title是文章标题,pubdate是发表日期,adminID是发表此文章的用户id。maxpage是文章的分页数量,对应user表的ID字段


访问记录表:access

+-----------+--------------------+------+-----+---------+----------------+ 
¦   Field           ¦   Type                               ¦   Null   ¦   Key   ¦   Default   ¦   Extra                     ¦ 
+-----------+--------------------+------+-----+---------+----------------+ 
¦   id                 ¦   int(4)   unsigned         ¦   NO       ¦   PRI   ¦   NULL         ¦   auto_increment   ¦ 
¦   aid               ¦   
int(4)   unsigned         ¦   NO       ¦           ¦                   ¦                                 ¦ 
¦   ipaddress   ¦   
varchar(15)                 ¦   YES     ¦   MUL   ¦   NULL         ¦                                 ¦ 
¦   time             ¦   
bigint(4)   unsigned   ¦   NO       ¦           ¦                   ¦                                 ¦ 
+-----------+--------------------+------+-----+---------+----------------+ 

id是此表的自动编号,自增,aid是文章id,对应文章表的ID,ipaddress是此次访问的ip地址,time为访问时间,类型是unix时间戳。


这三张表的关系为:user表的ID对应archives表的adminId,archives的ID对应access表的aid。


我现在写了个存储过程,用来计算从:
2007年9月24日到2007年11月15日(共52天)
所有用户(大概20个)
所发的所有点击量> =100的文章(共3831篇)
每篇文章每一天所带来的独立ip数量
把上述结果集插入到一张新表里面。


新表结构如下:

editor_record:

+----------+--------------------+------+-----+---------+-------+ 
¦   Field         ¦   Type                               ¦   Null   ¦   Key   ¦   Default   ¦   Extra   ¦ 
+----------+--------------------+------+-----+---------+-------+ 
¦   uid             ¦   int(10)                         ¦   NO       ¦           ¦                   ¦               ¦ 
¦   username   ¦   
varchar(30)                 ¦   NO       ¦           ¦                   ¦               ¦ 
¦   aid             ¦   
int(10)   unsigned       ¦   NO       ¦           ¦                   ¦               ¦ 
¦   title         ¦   
varchar(80)                 ¦   NO       ¦           ¦                   ¦               ¦ 
¦   pubdate     ¦   
int(11)                         ¦   NO       ¦           ¦   0               ¦               ¦ 
¦   maxpage     ¦   
int(4)                           ¦   YES     ¦           ¦   NULL         ¦               ¦ 
¦   click         ¦   
int(11)   unsigned       ¦   NO       ¦           ¦   0               ¦               ¦ 
¦   union_ip   ¦   
int(11)   unsigned       ¦   NO       ¦           ¦   0               ¦               ¦ 
¦   time           ¦   
bigint(4)   unsigned   ¦   NO       ¦           ¦                   ¦               ¦ 
+----------+--------------------+------+-----+---------+-------+ 

uid为发文章的用户id,username为发文章的用户名称,aid是文章id,title是文章标题,pubdate是文章发表时间,maxpage是文章的分页数量,click为文章的总点击量,union_ip是独立ip数量,time是日期。


这么做的目的是为了我前台一个php页面能够单表很迅速的查出我想要的数据,这个表有几个字段是冗余的,但我为了php可以快速进行单表查询,所以冗余就冗余吧。


计算一篇文章独立ip的方法为:

 

select access.aid,access.time,count(distinct(FROM_UNIXTIME(time,'%Y-%m-%d'))) as cnt from `access` where aid =文章id
 
group by c.aid




独立ip的算法是:如果一个ip地址在同一天内出现两次,只记一次,否则记它出现的次数。这个sql执行后,再sum一下cnt就是独立ip的数量。这张access的表有大概一百万条记录。


整个程序执行过程我们写了个存储过程,代码如下:

 

DELIMITER $$

DROP PROCEDURE IF EXISTS `mztest`.`proc_test1`$$
CREATE PROCEDURE `mztest`.`proc_test1` ()

BEGIN
DECLARE a int(11);
DECLARE b INT;
DECLARE days int(11);
DECLARE date int(11);
DECLARE cur_1 CURSOR FOR Select aid from tmp_table;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET b = 1;
CREATE TEMPORARY TABLE tmp_table (
    uid 
int(10NOT NULL,
    username 
varchar(30NOT NULL,
    aid 
int(10) unsigned NOT NULL
    title 
varchar(80NOT NULL,
    pubdate 
int(11NOT NULL default 0,
    maxpage 
int(4),
    click 
int(11) unsigned NOT NULL default 0
)TYPE
=HEAP DEFAULT CHARSET=gbk;

SET days=ABS(DATEDIFF(FROM_UNIXTIME("1190563200","%Y-%m-%%H:%i:%s"),FROM_UNIXTIME("1195142399","%Y-%m-%%H:%i:%s")));
SET date=1190563200;
insert into tmp_table Select b1.ID as uid,b1.userid,a1.ID as aid,a1.title,a1.pubdate,a1.maxpage,a1.click From archives a1, 
user b1 Where a1.adminid=b1.ID  And a1.click >= 100 ;
WHILE days > 0 DO
SET b=2;
  
OPEN cur_1;  
  REPEAT
    
FETCH cur_1 INTO a;
    
IF b=2 THEN
    
insert into editor_record(uid,username,aid,title,pubdate,maxpage,click,union_ip,time) select t.uid,t.username,c.aid,t.title,t.pubdate,t.maxpage,t.click,sum(cnt) as union_ip,date from (select access.aid,access.time,count(distinct(FROM_UNIXTIME(time,'%Y-%m-%d'))) as cnt from `access` where aid =And time >= date And time <= (date+86399group by ipaddress) c,tmp_table t where c.aid=t.aid and t.uid =1 group by c.aid;
    
END IF;
    UNTIL b 
= 1
  
END REPEAT;
  
CLOSE cur_1;
SET date=date+86400;
SET days = days-1
END WHILE;
END;$$

DELIMITER ;

之前,我是用PHP直接计算这些结果的,选出两个日期,和一个编辑的名称,计算这段时间段内的薪水,速度及其的慢,
而且这个表在我们网站的服务器上,查的次数多了,对网站的速度影响都是很大,领导斥令我把这个统计程序暂时不对兼职编辑开放.让我尽快采取优化方案.

于是,我想到了使用linux下的计划任务,定时在每天12点自动执行一段脚本,计算出当天的独立ip数量和编辑的薪水.第一次执行的时候我想先计算出9月24日那天到今天这段时间的数据,以后每一天计算当天的数据就可以了.把最终的结果插入到一个新表里面,我的php在前台单表查询就可以了,这样肯定会很快.其实流程就是:
把复杂的数据计算过程完全交给mysql来做,php用来把结果显示出来.

可是...虽然运行结果是正确的。但是执行速度非常之慢,预计要执行几天吧.也太长久了...
算了一下,大概要执行1000000*3831*52次!!!

一开始打算用perl写的,最近在学这个语言,和php比较像,用起来应该会比较顺手,想正好可以拿来练练.但是我在linux配了一天的DBI(DBD是perl连接mysql接口,DBI是mysql的驱动),始终就是配置不成功.身边也没有有相关经验的人.后来想到用linux的shell来写,但shell语言对复杂数据的处理能力有限,而且在我感觉语法有些怪异.于是就用mysql的存储过程来写,

目前一直在琢磨优化代码的方案,我的压力很大啊,一堆兼职编辑在等着我这个程序给人家结算薪水呢,数据有错或者不能尽快给人家结果的话,我良心过不去啊,唉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值