Php 非常具体的MySQL查询,我想改进
这是我的场景:我有一个包含事件的表,每个事件都有一个名为“created”的字段,该字段带有创建该事件的时间戳。现在我需要对事件从最新到最旧进行排序,但我不希望MySQL将它们全部返回。我只需要给定时间间隔内的最新数据,例如24小时范围内的数据(编辑:我希望有一个灵活的解决方案,不仅是24小时范围内的,而且可能每隔几个小时)。我只需要最后10天。我已经做到了这一点,但我相信这是最低效的方式,也就是说:Php 非常具体的MySQL查询,我想改进,php,mysql,Php,Mysql,这是我的场景:我有一个包含事件的表,每个事件都有一个名为“created”的字段,该字段带有创建该事件的时间戳。现在我需要对事件从最新到最旧进行排序,但我不希望MySQL将它们全部返回。我只需要给定时间间隔内的最新数据,例如24小时范围内的数据(编辑:我希望有一个灵活的解决方案,不仅是24小时范围内的,而且可能每隔几个小时)。我只需要最后10天。我已经做到了这一点,但我相信这是最低效的方式,也就是说: $timestamp = time(); for($i = 0; $i < 10; $
$timestamp = time();
for($i = 0; $i < 10; $i++) {
$query = "SELECT * FROM `eventos` WHERE ... AND `created` < '{$timestamp}' ORDER BY `created` DESC LIMIT 1";
$return = $database->query( $query );
if($database->num( $return ) > 0) {
$event = $database->fetch( $return );
$events[] = $event;
$timestamp = $timestamp - 86400;
}
}
$timestamp=time();
对于($i=0;$i<10;$i++){
$query=“通过`created`DESC LIMIT 1`从`eventos`中选择*并`created`<'{$timestamp}'顺序”;
$return=$database->query($query);
如果($database->num($return)>0){
$event=$database->fetch($return);
$events[]=$event;
$timestamp=$timestamp-86400;
}
}
我希望我说得够清楚了。谢谢
Jesús.您希望在10天内完成所有活动,还是在10天内每天只完成一个活动
无论哪种方式,考虑寻求帮助。它应该可以帮助您获得所需的日期范围。我会添加另一列,即日期(而不是时间),然后使用MySQL“group by”获取每个日期的最新值
本教程就是这样做的,但按产品类型而不是按日期。这应该有帮助 假设您希望在过去10天内每天发生最新(创建日期最大)的事件 因此,让我们每天获取最新的时间戳
$today = date('Y-m-d');
$tenDaysAgo = date('Y-m-d', strtotime('-10 day'));
$innerSql = "SELECT date_format(created, '%Y-%m-%d') day, MAX(created) max_created FROM eventos WHERE date_format(created, '%Y-%m-%d') BETWEEN '$today' and '$tenDaysAgo' GROUP BY date_format(created, '%Y-%m-%d')";
然后,我们可以选择与这些创建日期匹配的所有事件
$outerSql = "SELECT * FROM eventos INNER JOIN ($innerSql) as A WHERE eventos.created = A.max_created";
我还没有机会测试这一点,但原则应该足够合理
如果要按其他任意小时数分组,请更改innerSql:
$fromDate = '2012-07-06' // or if you want a specific time '2012-07-06 12:00:00'
$intervalInHours = 5;
$numberOfIntervals = 10;
$innerSql = "SELECT FLOOR(TIMESTAMPDIFF(HOUR, created, '$fromDate') / $intervalInHours) as grouping, MAX(created) as max_created FROM eventos WHERE created BETWEEN DATE_SUB('$fromDate', INTERVAL ($intervalInHours * $numberOfIntervals) HOUR) AND '$fromDate' GROUP BY FLOOR(TIMESTAMPDIFF(HOUR, created, '$fromDate') / $intervalInHours)";
如果您有一个以
created
作为前导列的索引,MySQL可能能够进行反向扫描。如果24小时内没有任何事件,则返回的行可能不是该时间段中的行。为了确保在该期间获得一行,您还需要在created
列中包含一个下限,如下所示:
SELECT * FROM `eventos`
WHERE ...
AND `created` < FROM_UNIXTIME( {$timestamp} )
AND `created` >= DATE_ADD(FROM_UNIXTIME( {$timestamp} ),INTERVAL -24 HOUR)
ORDER BY `created` DESC
LIMIT 1
从您的代码来看,24小时周期似乎是在任意时间限制的。。。如果time函数返回1341580800('2012-07-06 13:20'),则您的十个时段都是从给定日期的13:20到次日的13:20
(注意:如果您的参数是unix时间戳整数,请确保数据库对其进行了正确解释。)
在一个查询中提取十行可能更有效。如果可以保证“timestamp”是唯一的,那么就可以创建这样一个查询,但是查询文本将比现在复杂得多。我们可以在每个时段内获取MAX(timestamp_u2;),然后将其加入到行中。。。但那将是非常混乱的
如果我想把所有的十行都拉出来,我可能会尝试使用UNION-all
的方法,虽然不是很漂亮,但至少可以调整一下
SELECT p0.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p0
UNION ALL
SELECT p1.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p1
UNION ALL
SELECT p2.*
FROM ( SELECT * FROM `eventos` WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -3*24 HOUR)
ORDER BY `created` DESC LIMIT 1
) p2
UNION ALL
SELECT p3.*
FROM ...
然后把它放到你的桌子上
ON `created` < p.period_end
AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)
“创建”时的=DATE\u ADD(p.period\u end,INTERVAL-1*{$nsecs}秒)
通过p.period\u end将每个时段组的最大值(已创建)向后拉,并将其包装在内联视图中
然后将其连接回您的表以获得每一行
但这真的非常混乱,很难理解,而且不可能比你已经在做的事情更快(或更高效)。您可以做的最大改进是运行9个查询所需的时间
试试这个:
SELECT *
FROM eventos
WHERE created BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 10 DAY) AND DATE_ADD(DATE(NOW()), INTERVAL 1 DAY)
ORDER BY created DESC
LIMIT 10
这里有一个将为您带来过去10天中每天的第一件事
SELECT *
FROM eventos
WHERE created BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 10 DAY) AND DATE_ADD(DATE(NOW()), INTERVAL 1 DAY)
GROUP BY DATE(created)
ORDER BY MAX(created) DESC
LIMIT 10
我只想要10天内每天最新的答案。如果10天内每天最新的答案真的是你想要的,我相信我的第二个答案是迄今为止所有答案中最正确的。非常感谢你的回复,这是解决问题的好办法,但是如果我想要每5小时最新的答案呢?我需要一个更灵活的解决方案来改变时间间隔,我说每天都要简化,但还是要谢谢你D这个解决方案对我来说似乎很完美,但是如果时间戳间隔是5小时而不是每天,我应该做什么改变呢?我说每天一次来简化,谢谢你的时间!天数更容易,因为它们是数据中自然出现的组。你必须根据你的时间间隔创建一些人工组。你可以用你的时间间隔的模数来创建它。我已经更新了我的回复,使用的不仅仅是设定的天数。这是基于$fromDate值的小时间隔。注意:为了避免在一段时间内返回多行,您需要保证
timestamp
列的唯一性。我刚刚意识到这是错误的。你想要过去十天里每天最新的活动。这将给你最近的10个事件,最多10天。或者也许这没有错。我不太确定你在问什么。无论如何,我补充了另一个答案。希望这两个选项中的一个是您所追求的。以下是决定一天间隔的按日期分组(创建)
DATE(created)
只是created
的日期部分,没有时间。因此,如果您从每天(DATE(created)
)获得最新的事件(MAX(created)
),这将为您提供您想要的。如果你想要一天以外的时间间隔,我相信你必须以某种方式分组,而不是DATE(created)
。例如,如果你想得到每小时而不是每天的第一篇帖子,你可以按CONCAT(DATE(created),'',hour(created))分组。基本上,我们的想法是将创建的,
,四舍五入到最接近的值,然后按该值分组
SELECT *
FROM eventos
WHERE created BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 10 DAY) AND DATE_ADD(DATE(NOW()), INTERVAL 1 DAY)
ORDER BY created DESC
LIMIT 10
SELECT *
FROM eventos
WHERE created BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 10 DAY) AND DATE_ADD(DATE(NOW()), INTERVAL 1 DAY)
GROUP BY DATE(created)
ORDER BY MAX(created) DESC
LIMIT 10