你将要阅读的内容相当老套,所以不要在家里尝试这个!
在 SQL 中,您的问题的答案通常是NO,但由于( @bluefeetGROUP BY
提到的)的宽松模式,MySQL 中的答案是YES。
假设,您在 (post_status, post_type, post_author, post_date) 上有一个 BTREE 索引。索引在引擎盖下的样子如何?
(post_status='publish', post_type='post', post_author='user A', post_date='2012-12-01') (post_status='publish', post_type='post', post_author='user A', post_date='2012-12-31') (post_status='publish', post_type='post', post_author='user B', post_date='2012-10-01') (post_status='publish', post_type=' post', post_author='用户 B', post_date='2012-12-01')
也就是说,数据按所有这些字段升序排序。
GROUP BY
默认情况下,它会按分组字段对数据进行排序(在post_author
我们的例子中;post_status,post_type 是WHERE
子句需要的),如果有匹配的索引,它会按升序获取每个第一条记录的数据。也就是说,查询将获取以下内容(每个用户的第一篇文章):
(post_status='publish', post_type='post', post_author='user A', post_date='2012-12-01') (post_status='publish', post_type='post', post_author='user B', post_date='2012-10-01')
但是GROUP BY
在 MySQL 中允许你显式地指定顺序。当你post_user
按降序请求时,它会以相反的顺序遍历我们的索引,仍然为每个组取第一个记录,实际上是最后一个。
那是
...
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC
会给我们
(post_status='publish', post_type='post', post_author='user B', post_date='2012-12-01') (post_status='publish', post_type='post', post_author='user A', post_date='2012-12-31')
现在,当您按 post_date 对分组结果进行排序时,您将获得所需的数据。
SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC
ORDER BY wp_posts.post_date DESC;
注意:
对于这个特定的查询,我不建议这样做。在这种情况下,我会使用@bluefeet建议的稍微修改的版本。但这种技术可能非常有用。在这里看看我的答案:检索每组中的最后一条记录
陷阱:该方法的缺点是
- 查询的结果依赖于索引,这与 SQL 的精神背道而驰(索引应该只加快查询速度);
- 索引不知道它对查询的影响(您或其他人将来可能会发现索引太耗费资源并以某种方式更改它,从而破坏查询结果,而不仅仅是它的性能)
- 如果您不了解查询的工作原理,您很可能会在一个月内忘记解释,并且查询会使您和您的同事感到困惑。
优点是在困难情况下的性能。在这种情况下,查询的性能应该与@bluefeet 的查询相同,因为排序涉及的数据量很大(所有数据都加载到临时表中然后排序;顺便说一句,他的查询(post_status, post_type, post_author, post_date)
也需要索引) .
我会建议:
正如我所说,这些查询使 MySQL 浪费时间对临时表中潜在的大量数据进行排序。如果您需要分页(即涉及 LIMIT),大部分数据甚至会被丢弃。我要做的是最小化排序数据的数量:即排序并限制子查询中的最小数据,然后连接回整个表。
SELECT *
FROM wp_posts
INNER JOIN
(
SELECT max(post_date) post_date, post_author
FROM wp_posts
WHERE post_status='publish' AND post_type='post'
GROUP BY post_author
ORDER BY post_date DESC
-- LIMIT GOES HERE
) p2 USING (post_author, post_date)
WHERE post_status='publish' AND post_type='post';
使用上述方法的相同查询:
SELECT *
FROM (
SELECT post_id
FROM wp_posts
WHERE post_status='publish' AND post_type='post'
GROUP BY post_author DESC
ORDER BY post_date DESC
-- LIMIT GOES HERE
) as ids
JOIN wp_posts USING (post_id);
所有这些查询及其在SQLFiddle上的执行计划。