我写了一个统计/跟踪平台来监控我的网站活动。对于每个用户,在表格中创建一个条目,其中包含一些相关信息:IP,Ref,GeoLocate国家代码等。
数据库包含超过7MM的结果,大小约为4GB。
现在,我有一个脚本,必须进行SUM查询才能获得定义时间间隔内的展示次数,点击次数等($ from_date& $ to_date)。
$query = "SELECT COUNT(ip) as tot, sum(clicked=0) as a0, sum(clicked=1) as a1, sum(converted=0) as a2, sum(converted=1) as a3 FROM tf_data WHERE cid='".$cid."' and stamp between ".$from_date." and ".$to_date." ";
单独这个查询需要FOREVER加载,即使我在一个体面的VPS机器上。我在我的摘要页面中有一些其他类似的查询,这会导致脚本频繁超时(请求超时:此请求需要很长时间才能处理,服务器会超时。如果不应该超时,请联系管理员这个网站增加'连接超时'。)
我该怎么办?我该如何处理大量的数据?我应该创建一个单独的表并运行一个cron作业来插入/更新印象数,点击数......?
这样的事情通常如何完成?
一如既往地谢谢!
编辑:表格结构:
CREATE TABLE `tf_data` (
`click_id` int(11) NOT NULL AUTO_INCREMENT,
`ip` varchar(225) NOT NULL,
`agent` text NOT NULL,
`referer` text NOT NULL,
`stamp` text NOT NULL,
`country` varchar(30) NOT NULL,
`src` text NOT NULL,
`adspot` varchar(250) NOT NULL,
`cid` text NOT NULL,
`adid` text NOT NULL,
`lp` varchar(250) NOT NULL,
`offer` int(11) NOT NULL,
`clicked` int(11) NOT NULL,
`converted` int(11) NOT NULL,
`converted2` int(11) NOT NULL,
`price` varchar(255) NOT NULL,
PRIMARY KEY (`click_id`),
UNIQUE KEY `ip` (`ip`)
) ENGINE=MyISAM AUTO_INCREMENT=9599999 DEFAULT CHARSET=latin1
答案 0 :(得分:4)
首先,如果标记是你的时间戳(我假设它是),将其转换为此类并在其上放置索引,这将允许您更轻松地访问数据的小子集(按日期)。
然后创建一个汇总表,每天对所有现有数据进行此计算,然后进行日常工作以使其保持最新状态。
这样,对于历史用法,您只需要查看(小得多)摘要表,并可能查看自上次摘要以来的新行。
如果你不总是需要查看所有数据,你也可以考虑查看表分区(无论是built in还是差的人),这样你仍然可以引用所有数据作为一个整体当你需要时,但只有在速度需要时才能访问它的一个子集。
答案 1 :(得分:2)
700万行并不是那么多。普通的WHERE子句返回多少行?
每当遇到查询性能问题时,look at the query execution plan。
问问自己,“我有合适的数据类型吗?”正如Matthew Watson指出的那样,该表中没有时间戳(DATETIME)数据类型。在这种情况下,使用DATETIME而不是TEXT可能会使数据库的大小减少大约10个字节。 (我猜“邮票”可能是DATE而不是DATETIME。减少节省,但仍然节省,并且没有日期比较的转换。)
问问自己,“我可以改进索引吗?”您至少需要“cid”和“stamp”上的索引。
问问自己,“我可以减少基表或查询中的列数吗?” (“转换”和“转换2”的组合是可疑的。)
问问自己,“我可以减少行数吗?”
完成所有操作后,请考虑partitioning。
分区后(或可能在分区之前)考虑使用OLAP表进行汇总。
答案 2 :(得分:1)
我建议离线计算+表格分区+ cid上的HASH索引和邮票上的BTree索引作为快速解决方案。长期解决方案是使用Noss数据存储解决方案,如Cassandra和Hadoop + Pig来计算并将数据推送到Cassandra。