2008-12-14 39 views
2

我有一個文章表和一個分類表。我想爲每個類別獲取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 

使用說明,它讓我看到它在做一個連接類型的所有& REF。選擇類型是PRIMARY和DEPENDENT SUBQUERY。

有沒有更好的解決方案?

+0

這看起來可以獲得少於7個的類別的所有文章。這似乎與您的目標的英文說明略有不同。例如,如果一個類別包含十篇文章,那麼您的描述聽起來像是希望其中的7個,而不是0. – recursive 2008-12-16 04:40:27

回答

0

你有幾個選擇 - 有些可能會導致性能問題,但它取決於很多因素。

你可以將它分成幾個查詢。一個查詢讀出所有類別:

SELECT categories_id FROM Categories 

然後爲每個類別,讀出排名前七位的文章:

SELECT 
    id, 
    title, 
    ...etc. 
FROM articles 
where categories_id = 1 

...等每個類別。

這有利於理解,但缺點是它將一個查詢變成1 +(1 *貓數)。然後再次,你可以限制類別的數量,這樣你就可以控制一些元素。有時你會發現5個簡單的查詢比1個複雜的查詢執行得更好!

這種假設你是從你控制的一些代碼調用SQL - 是這種情況嗎?

+0

我從來沒有見過將子查詢分解爲帶有子查詢的循環的情況提高了性能,除非第一次出現了一些可解決的錯誤。 – dkretz 2008-12-14 20:36:42

2
  1. 表格有多大,速度有多慢?

  2. 表上有哪些索引?

  3. EXPLAIN的全部信息是什麼?

另外,兩個日期時間值是明確的,所以它看起來像這樣正在從一些其他信息構成它生成的代碼生成無論是。是否有另一種SQL查詢,它是在列表中的一個循環內執行的?

目前還不清楚哪7種文章被選中 - 最近的?到哪一天?

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 
+0

僅限於最新版本具有MySQL支持的子查詢;並且優化對他們來說不是很好。所以這是可測試的,但需要與其他類型的方法進行比較。 – dkretz 2008-12-14 20:40:23

+0

將LIMIT 7放入子查詢中不會限制行數 - 它只是限制子查詢中匹配的記錄數。更好的是在子查詢中選擇DISTINCT - 那麼它只會查看每個類別的一行,而不是7 – dkretz 2008-12-14 21:39:12

+0

好點,最初不清楚他是想要每個類別中的前7行還是小於7的範圍,並且最近澄清了它作爲每個分揀的最新7篇文章。 – Turnkey 2008-12-14 23:09:06

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是什麼樣的。)

編輯:改變 「< 7」 到< = 7"

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)。有一個少於七篇符合該標準的文章,那麼當前文章必須屬於其最新版本。

如果你可以依靠具有相同的排序順序爲pubdate獨特id列,那麼你就可以簡化連接,因爲將有超過一個獨特的列沒有關係:

ON (a1.categories_id = a2.categories_id AND a1.id < a2.id) 
0

儘管比爾的查詢可能工作平均情況好一點,一次運行就花了230秒。我沒有做一個完整的測試(幾次運行),但它仍然太慢,所以我想更好的選擇是每個類別執行1個查詢,獲取最新的7個項目 - 看起來它將比所有其他選項更快。