我正在使用Amazon S3为播客提供MP3文件。亚马逊提供访问日志,我正在获取并存储在MySQL数据库中。数据库如下所示:
request_id varchar(16)
time int(10)
file varchar(255)
sent bigint(20)
size bigint(20)
status smallint(5)
ip varchar(39)
referrer varchar(255)
user_agent varchar(255)
因为这是一个播客,大量的点击是206范围请求(来自iTunes / iOS),请求小块的每个文件。
我也有一些人不止一次下载文件。
所以我要做的是构建一个查询:
sent
列)相加,这样我就可以看到该特定文件/ IP组合的所有范围请求的总和。sent
列的总和,只返回该结果,如果该总和的字节数是> = size
列的75%(目前我是用PHP做这个比较后查询。)以下是我目前正在使用的内容,我相信正在使用,但GROUP BY
的完整后果对我来说是个谜(例如 - {{1}中的列顺序1}}问题?):
GROUP BY
有人看到任何潜在的陷阱吗?
答案 0 :(得分:3)
首先回答你的问题:
“group by”中列的顺序与结果中返回的内容无关。
您将始终获得相同的分组和相同的聚合值。但是如果列上有索引并且group by中的顺序与索引中列的顺序不匹配,则可能会影响mysql中的性能。我曾经看过一篇关于性能影响的文章。如果我找到它,我会发布它的链接。
至于您的查询,请注意您选择的字段不属于该组。这不是SQL的标准,但是MySql允许这个(它可以告诉MySql禁止它)。您需要知道的是引擎将创建组,对于这些字段,它将从组中遇到的第一行中选择第一个值。您的查询方式,这不能保证正确的结果。原因是订单在完成后应用于结果。几乎没有可能的解决方案,但我会提到使用子查询并在内部订购以确保在分组发生之前第一行是您需要的那些。
SELECT in_tab.date, in_tab.ip, in_tab.file, SUM(in_tab.sent), in_tab.size
FROM (
SELECT FROM_UNIXTIME(time,'%M %D') as date, ip, file, sent, size
FROM stats
WHERE sent > 0
AND size > 0
AND FROM_UNIXTIME(time, '%Y-%m-%d') >= '2012-09-01'
AND FROM_UNIXTIME(time, '%Y-%m-%d') <= '2012-09-30'
ORDER BY time ASC
) in_tab
GROUP BY in_tab.ip, in_tab.file
ORDER BY in_tab.date ASC, in_tab.file ASC
如您所见,子查询中的顺序是在分组开始之前执行的。因此,在外部查询生成的每个组中,字段的日期和大小将从第一行获取,一行将具有最早的日期(如果您想要最近的,则在子查询中更改为DESC)。外部订单用于对最终结果进行排序,您可以根据需要进行更改。
现在对于BONUS:为了只有那些总和> = 75%的结果,你可以使用HAVING子句:
SELECT in_tab.date, in_tab.ip, in_tab.file, SUM(in_tab.sent) as total_sent, in_tab.size
FROM (
SELECT FROM_UNIXTIME(time,'%M %D') as date, ip, file, sent, size
FROM stats
WHERE sent > 0
AND size > 0
AND FROM_UNIXTIME(time, '%Y-%m-%d') >= '2012-09-01'
AND FROM_UNIXTIME(time, '%Y-%m-%d') <= '2012-09-30'
ORDER BY time ASC
) in_tab
GROUP BY in_tab.ip, in_tab.file
HAVING total_sent > = 0.75 * in_tab.size
ORDER BY in_tab.date ASC, in_tab.file ASC
我建议你考虑最好的解决方案:切换到标准的sql。从长远来看,它更好,更安全。然后,您将在一个查询中对所需数据进行分组,并在另一个查询中(或使用连接)获取其他信息(如文件大小和最小/最大日期)。答案已经很长了,我将不得不停止解释并举例说明。
答案 1 :(得分:0)
按列顺序分组很重要,它按第一列分组,然后按下一个分组,以便A,B分组将结果分组为A然后分组B,这对于B是类似的数据很重要。