首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 求一些优化方案,分不够可以另开贴再加! [已结贴,结贴人:ShadowSniper]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-16 21:17:07 楼主
    用户表: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的方法为:
    SQL code
    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的表有大概1000000万条记录。


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

    SQL code
    交谈中请勿轻信汇款、中奖消息,勿轻易拨打陌生电话。 似水流年 2007-11-16 20:49:04 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(10) NOT NULL, username varchar(30) NOT NULL, aid int(10) unsigned NOT NULL, title varchar(80) NOT NULL, pubdate int(11) NOT 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-%d %H:%i:%s"),FROM_UNIXTIME("1195142399","%Y-%m-%d %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 =a And time >= date And time <= (date+86399) group 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 ;



    存储过程可以执行,结果也是正确的。但是执行速度非常之慢,预计要执行几天吧。。。
    算了一下,大概要执行1000000*3831*52次!!!

    数据量大,计算复杂是一方面,但我还是想请教下,我的程序逻辑是不是有问题?是不是兜了很多圈子?有没有可以优化的策略?谢谢!分不够可以再开贴另加,只求各位能给点优化建议和方案,因为一大堆兼职编辑人员的薪水需要我这个程序来计算,肩负的压力非常之大。再次感谢。
    100  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-16 22:29:471楼 得分:0
    http://blog.chinaunix.net/u/29134/showart_400939.html
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-17 00:29:012楼 得分:0
    比较有意思,思考中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-17 02:45:343楼 得分:20
    我觉得可以把一堆操作拆开来做,这样数据库本身的优化器更能发挥作用。这就是我的想法。

    以下是代码,没有完全测试,如果有语法错误及时提出来:
    SQL code
    DELIMITER $$ DROP PROCEDURE IF EXISTS `mztest`.`proc_test1`$$ CREATE PROCEDURE `mztest`.`proc_test1` () -- 创建文章aid 与 总的点击次数click的映射表 create table archive_click ( aid int PRIMARY KEY, click int ); insert into archive_click(aid,click) select aid, count(*) from access group by aid order by aid; -- 创建具有少量必要信息的临时表 -- tmp1_table大小约为1,000,000 -- 因为archive_click表中aid为主码,所以速度不会很慢 create table tmp1_table select aid, FROM_UNIXTIME(time,"%Y-%m-%d") date, ipaddress from access as A, archive_click as B where A.aid = B.aid and B.click >= 100; -- 分组统计,得到union_ip -- tmp2_table大小约为3831*52 = 200,000 -- 主要是一个排序过程,时间复杂度为O(nlogn) = 4,000,000 create table tmp2_table select aid, date, count(distinct(ipadress)) union_ip from tmp1_table group by aid,date; -- 将所有信息融合到一个表中 -- 由于都是主码上的连接,所以速度也不会很慢 -- 如果慢的话,这里改起来也容易 create table editor_record select U.ID uid, U.userid username, T2.aid aid, A.title title, A.pubdate pubdate, A.maxpage maxpage, T1.click click, T2.union_ip union_ip, T2.date time from tmp2_table T2, tmp1_table T1, archives A, user U where T2.aid = T1.aid and T2.aid = A.id and A.adminID = U.ID; drop table archive_click; drop table tmp1_table; drop table tmp2_table; END $$ DELIMITER ;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • cowbo
    • 等级:
    发表于:2007-11-17 09:42:284楼 得分:0



    漂过~~~~~~~~~~~~~~~~~~~~~

    友情UP.....

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-17 13:05:515楼 得分:0
    to qzy6:错误提示:
    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 'create table archive_click
    (
    aid int PRIMARY KEY,
    click int
    );
    insert into archi' at line 2
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-17 14:50:076楼 得分:0
    我上面发的代码确实有些错误,昨晚有点晕,不好意思。
    下面的代码是一系列sql查询,不需要建立procedure。
    我觉得在效率上应当比较快,我想整个执行过程不会超过一分钟。 因为楼主是自己写循环,要执行很多次查询,代价是很大的。
    如果没有错误,希望楼主把执行时间告诉我。

    以下代码在mysql 5.0上执行通过:
    SQL code
    -- 选择数据库 use mztest; -- 以下是创建楼主需要的表,用于测试 create table user ( ID int(10) PRIMARY KEY auto_increment , userid varchar(30) ); create table archives ( ID int(11) unsigned PRIMARY KEY auto_increment , click int(11) unsigned , title varchar(80) , pubdate int(11), adminID int(11) , maxpage int(4) ); create table access ( id int(4) PRIMARY KEY auto_increment , aid int(4), ipaddress varchar(15), time bigint(4) ); -- 创建文章aid与总的点击次数click的映射表 create table archive_click ( aid int(11) PRIMARY KEY, click int(11) ); create table tmp1_table select A.aid, FROM_UNIXTIME(time,"%Y-%m-%d") date, ipaddress from access as A, archive_click as B where A.aid = B.aid and B.click >= 100; -- 创建具有少量必要信息的临时表 -- 得到tmp1_table大小约为1,000,000 -- 执行过程中因为archive_click表中aid为主码,所以速度不会很慢 create table tmp2_table select aid, date, count(*) click, count(distinct(ipaddress)) union_ip from tmp1_table group by aid,date; -- 分组统计,得到单日的click和union_ip -- 得到tmp2_table大小约为3831*52 = 200,000 -- 执行主要是对tmp1_table表中元组一个排序过程,时间复杂度为O(nlogn)=20,000,000 create table editor_record select U.ID uid, U.userid username, T.aid aid, A.title title, A.pubdate pubdate, A.maxpage maxpage, T.click click, T.union_ip union_ip, T.date time from tmp2_table T, archives A, user U where T.aid = A.id and A.adminID = U.ID; -- 删除临时表 drop table tmp1_table; drop table tmp2_table; drop table archive_click;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-17 14:54:197楼 得分:0
    晕,上面写错位了,再贴:
    SQL code
    -- 选择数据库 use mztest; -- 以下是创建楼主需要的表,用于测试 create table user ( ID int(10) PRIMARY KEY auto_increment , userid varchar(30) ); create table archives ( ID int(11) unsigned PRIMARY KEY auto_increment , click int(11) unsigned , title varchar(80) , pubdate int(11), adminID int(11) , maxpage int(4) ); create table access ( id int(4) PRIMARY KEY auto_increment , aid int(4), ipaddress varchar(15), time bigint(4) ); -- 创建文章aid与总的点击次数click的映射表 create table archive_click ( aid int(11) PRIMARY KEY, click int(11) ); insert into archive_click(aid,click) select aid, count(*) from access group by aid order by aid; -- 创建具有少量必要信息的临时表 -- 得到tmp1_table大小约为1,000,000 -- 执行过程中因为archive_click表中aid为主码,所以速度不会很慢 create table tmp1_table select A.aid, FROM_UNIXTIME(time,"%Y-%m-%d") date, ipaddress from access as A, archive_click as B where A.aid = B.aid and B.click >= 100; -- 分组统计,得到单日的click和union_ip -- 得到tmp2_table大小约为3831*52 = 200,000 -- 执行主要是对tmp1_table表中元组一个排序过程,时间复杂度为O(nlogn)=20,000,000 create table tmp2_table select aid, date, count(*) click, count(distinct(ipaddress)) union_ip from tmp1_table group by aid,date; -- 将所有信息融合到一个表中 -- 由于都是主码上的连接,所以速度也不会很慢 create table editor_record select U.ID uid, U.userid username, T.aid aid, A.title title, A.pubdate pubdate, A.maxpage maxpage, T.click click, T.union_ip union_ip, T.date time from tmp2_table T, archives A, user U where T.aid = A.id and A.adminID = U.ID; -- 删除临时表 drop table tmp1_table; drop table tmp2_table; drop table archive_click;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-20 16:36:138楼 得分:80
    我是DF的GF,接分~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-20 16:48:519楼 得分:0
    谢谢qzy6的热情帮忙,也谢谢DF的GF帮我解决了问题
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-20 16:58:0510楼 得分:0
    不客气,以后多多交流,你的存储过程我也在学习中。
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved