如何查询上个月的10个最新项目或项目,以哪个为准?

时间:2008-12-06 18:25:16

标签: sql mysql

在我的博客上,我想显示上个月的所有帖子。但如果这不到10个帖子,我想显示最近的10个帖子(换句话说,首页上的帖子永远不应少于10个)。我想知道是否有办法在单个查询中执行此操作?

目前,我首先运行此查询:

select count(*) from posts where timestamp > ($thirty_days_ago)
order by timestamp desc

如果该计数大于或等于10:

select * from posts where timestamp > ($thirty_days_ago)
order by timestamp desc

否则:

select * from posts order by timestamp desc limit 10

但是这需要我运行两个查询。使用单个查询有更有效的方法吗? (我正在使用MySQL。)

7 个答案:

答案 0 :(得分:5)

(SELECT * FROM posts
WHERE `timestamp` >= NOW() - INTERVAL 30 DAY)
UNION
(SELECT * FROM posts
ORDER BY `timestamp` DESC
LIMIT 10);

编辑:回复@ doofledorfer的评论:我在我的测试数据库上运行了它,它运行正常。我尝试将timestamp与日期文字以及常量表达式进行比较,如上面的查询所示,但它对优化计划没有任何影响。当然,我使用了大量的数据,如果有数千行,优化计划可能会有所不同。

在任何情况下,OP都在询问如何在单个查询中获得正确的结果,如何使执行计划达到最佳状态。毕竟这是一个UNION查询,并且必然会产生一个filesort。

+------+--------------+------------+------+---------------+------+---------+------+------+----------------+
| id   | select_type  | table      | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+------+--------------+------------+------+---------------+------+---------+------+------+----------------+
|  1   | PRIMARY      | posts      | ALL  | timestamp     | NULL | NULL    | NULL |   20 | Using where    | 
|  2   | UNION        | posts      | ALL  | NULL          | NULL | NULL    | NULL |   20 | Using filesort | 
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL | NULL    | NULL | NULL |                | 
+------+--------------+------------+------+---------------+------+---------+------+------+----------------+

答案 1 :(得分:2)

这样做:

select * from posts order by timestamp desc limit 100

并在内存中进一步过滤结果。 (假设100是人们希望在一个页面中看到的“一个月内的帖子”的实际上限)

这是“更有效的单一查询”。

答案 2 :(得分:1)

我只能看到一个查询的唯一方法就是“按时间戳选择帖子”,返回所有帖子,然后处理代码中的显示逻辑。但是,这不是一个非常有效的解决方案。

只要您正确索引表,然后执行选择计数(*)后跟检索查询不应影响性能。是否有任何特殊情况会让您专门尝试避免第二次查询?否则,我认为您的解决方案就足够了。

答案 3 :(得分:1)

不,没有更有效的方法。我会按你在问题中描述的方式来做。 Bill Karwin的答案大致相当于如果修改谓词,就像我上面评论的那样。

到目前为止,我看到的所有其他建议效率都低得多,即使它们以某种方式返回了正确的结果。

答案 4 :(得分:1)

您正在寻找单个表扫描(例如一个SELECT)吗?或者单程往返数据库服务器?比尔的答案只有一次往返,但是有两个SELECT ...所以这是否构成一个或两个“查询”取决于当你说“查询”时你实际上在寻找什么。

如果您对数据库的延迟非常高,比如Bill的解决方案最好,因为您不会非常等待通信。如果加载数据库本身并且表扫描很昂贵,那么原始实现可能会更好,原因有两个:

  • 您可以缓存COUNT结果,因此每10分钟左右才会执行一次。现在,您已经有效地摊销了该查询的费用(如果在10分钟内有200位访问者访问该页面,那么您只发出了201条SELECT语句。)
  • 数据库引擎可以优化COUNT查询以命中索引而不是完整表,这比尝试将UNION几个数据集放在一起要快得多。我不确定MySQL是否足够复杂。

答案 5 :(得分:0)

我认为你可以尝试类似的东西:

select * from posts 
where (timestamp >= (NOW() - INTERVAL 30 DAY)) or 
(post_id in (select post_id from posts order by timestamp desc limit 10))
order by timestamp desc

答案 6 :(得分:-1)

Idea1 :执行查询以始终获取本月的帖子。然后做一个循环,计算提取的帖子数量。如果且仅当此数字小于10时,执行第二次查询。

创意2 :为什么不缓存您的第一个查询(Google App Engine,例如,有缓存API)?本月的帖子数量不太可能经常更改,因此在大多数情况下您不需要第一个查询。