我有一个文章表和一个类别表。我想为每个类别获取7篇文章。目前我有这个,但它在大型桌子上的速度很慢,所以它不是一个真正的解决方案:
SELECT id,
title,
categories_id,
body,
DATE_FORMAT(pubdate, "%d/%m/%y %H:%i") as pubdate
FROM articles AS t
WHERE (
SELECT COUNT(*)
FROM articles
WHERE t.categories_id = categories_id
AND id< t.id AND publish = 1
AND expires > '2008-12-14 18:38:02'
AND pubdate <= '2008-12-14 18:38:02'
) < 7
ORDER BY categories_id DESC
使用说明,它显示我正在进行连接类型ALL&amp; REF。选择类型是PRIMARY和DEPENDENT SUBQUERY。
有更好的解决方案吗?
答案 0 :(得分:4)
以下是我如何解决这个问题:
SELECT a1.id,
a1.title,
a1.categories_id,
a1.body,
DATE_FORMAT(a1.pubdate, "%d/%m/%y %H:%i") as pubdate
FROM articles AS a1
LEFT OUTER JOIN articles AS a2
ON (a1.categories_id = a2.categories_id AND
(a1.pubdate < a2.pubdate OR (a1.pubdate = a2.pubdate AND a1.id < a2.id)))
GROUP BY a1.id
HAVING COUNT(*) < 7;
相关子查询通常表现不佳,因此该技术使用连接。
对于给定的文章,搜索与所考虑的当前文章的类别(a1)匹配的文章(a2),并且具有更新的日期(或者在平局的情况下更高id
)。如果满足该标准的文章少于七篇,那么当前的文章必须属于其最新类别。
如果您可以依赖与id
具有相同排序顺序的唯一pubdate
列,那么您可以简化连接,因为在唯一列上没有关联:
ON (a1.categories_id = a2.categories_id AND a1.id < a2.id)
答案 1 :(得分:2)
桌子有多大,慢得多慢?
桌子上有哪些索引?
EXPLAIN的全部信息是什么?
此外,两个日期时间值是显式的,因此看起来这是从由其他信息组成的代码生成的代码生成的。是否存在某种类型的SQL查询,它在列表的循环中执行它?
目前尚不清楚哪7篇文章被选中 - 最新?到哪几天?
答案 2 :(得分:1)
所以看起来你要求的文章少于7篇;这就是查询应该从哪里开始 -
SELECT categories_id, COUNT(1)
FROM articles
WHERE publish = 1
AND expires > '2008-12-14 18:38:02'
AND pubdate <= '2008-12-14 18:38:02'
GROUP BY categories_id
HAVING COUNT(1) < 7
然后用:
创建一个子查询SELECT
c.id, c.title, c.id, a.body,
DATEFORMAT(a.pubdate, "%d/%m/%y %H:%i") as pubdate
FROM categories c
JOIN articles a ON c.id = a.categories_id
JOIN
(
SELECT DISTINCT categories_id
FROM articles
WHERE publish = 1
AND expires > '2008-12-14 18:38:02'
AND pubdate <= '2008-12-14 18:38:02'
GROUP BY categories_id
HAVING COUNT(1) <= 7
) AS j ON c.id = j.categories_id
ORDER BY whatever
下一步是将返回的文章数限制为7 - 如果这看起来合适,我可以处理下一篇文章。 (按原样试试看看EXPLAIN的样子。)
编辑:将“&lt; 7”更改为&lt; = 7“
答案 3 :(得分:0)
您有多种选择 - 有些可能会导致性能问题,但这取决于很多因素。
您可以将其拆分为多个查询。一个查询读出所有类别:
SELECT categories_id FROM Categories
然后对于每个类别,请阅读前七篇文章:
SELECT
id,
title,
...etc.
FROM articles
where categories_id = 1
......等等每个类别。
这有一个简单易懂的好处,但缺点是它将一个查询转换为1 +(1 *猫数)。然后,你可以限制类别的数量,这样你就有了一些控制元素。有时您会发现5个简单查询比1个复杂查询执行得更好!
这种假设您从一些您可以控制的代码调用SQL - 是这种情况吗?
答案 4 :(得分:0)
在测试中我发现限制7在MySQL的子查询中不起作用,请参阅Bill的建议,我证实它运行良好。
SELECT id,
title,
categories_id,
body,
DATE_FORMAT(pubdate, "%d/%m/%y %H:%i") as pubdate
FROM articles A INNER JOIN articles B ON B.categories_ID = A.Categories_ID
WHERE A.ID IN (
SELECT ID
FROM Articles
WHERE categories_id = A.categories_id
AND publish = 1
AND expires > '2008-12-14 18:38:02'
AND pubdate <= '2008-12-14 18:38:02'
LIMIT 7
ORDER BY Categories_ID DESC)
ORDER BY B.Categories_ID DESC
答案 5 :(得分:0)
虽然比尔的查询平均可能会有所改善,但一次运行需要230秒。我没有做一个完整的测试(几次运行),但它仍然太慢所以我想更好的选择是每个类别获取最新的7个项目进行1次查询 - 看起来它会比所有其他选项更快。