如果您有一个索引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
我认为这里性能的关键是索引created
作为前导列,以及 WHERE 子句中引用的所有(或大多数)其他列,并确保您的查询使用该索引。
如果您需要不同的时间间隔,直到秒,这种方法可以很容易地推广。
SELECT * FROM `eventos`
WHERE ...
AND `created` < DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL 0*{$nsecs} SECOND)
AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*{$nsecs} SECOND)
ORDER BY `created` DESC
LIMIT 1
从您的代码来看,24 小时周期似乎是在任意时间有界的......如果时间函数返回例如 1341580800('2012-07-06 13:20'),那么您的十个周期都将来自 13当天20点到次日13点20分。
(注意:请确保如果您的参数是 unix 时间戳整数,那么数据库会正确解释它。)
在单个查询中提取十行可能更有效。如果可以保证 'timestamp' 是唯一的,则可以制作这样的查询,但查询文本将比您现在拥有的要复杂得多。我们可以在每个周期内获取 MAX(timestamp_) ,然后将其加入以获取行......但这将非常混乱。
如果我要尝试拉出所有十行,我可能会尝试采用一种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 ...
同样,这可以概括为在几秒钟内作为参数传递。将 HOUR 替换为 SECOND,并将“24”替换为具有秒数的绑定参数。
它相当冗长,但它应该运行良好。
另一种在单个结果集中获取它的非常混乱和复杂的方法是使用内联视图来获取十个周期的结束时间戳,如下所示:
SELECT p.period_end
FROM (SELECT DATE_ADD(t.t_,INTERVAL -1 * i.i_* {$nsecs} SECOND) AS period_end
FROM (SELECT FROM_UNIXTIME( {$timestamp} ) AS t_) t
JOIN (SELECT 0 AS i_
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) i
) p
然后把它加入你的桌子......
ON `created` < p.period_end
AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)
并为每个周期 GROUP BY p.period_end 拉回 MAX(created),将其包装在一个内联视图中。
然后将其连接回您的表格以获取每一行。
但这真的非常非常混乱,难以理解,而且不太可能比你已经在做的更快(或更高效)。您可以做出的最大改进是运行 9 个查询所需的时间。