2009-07-07 134 views
6

我使用MySQL爲我的網站構建了一個自定義論壇。該列表頁面本質上是具有以下列的表格:主題,最近更新#回覆優化MySQL查詢以避免「使用where;使用臨時;使用filesort」

db表有以下欄目:

id 
name 
body 
date 
topic_id 
email 

一個話題具有 「0」 的topic_id,和回覆有自己的母話題的topic_id。

SELECT SQL_CALC_FOUND_ROWS 
    t.id, t.name, MAX(COALESCE(r.date, t.date)) AS date, COUNT(r.id) AS replies 
FROM 
    wp_pod_tbl_forum t 
LEFT OUTER JOIN 
    wp_pod_tbl_forum r ON (r.topic_id = t.id) 
WHERE 
    t.topic_id = 0 
GROUP BY 
    t.id 
ORDER BY 
    date DESC LIMIT 0,20; 

總共有約2,100個項目在這個表中,查詢通常需要高達6秒。我在「topic_id」列中添加了一個INDEX,但沒有多大幫助。有沒有什麼方法可以加速這個查詢,而不用做重大的重組?

編輯:還沒有工作。我似乎無法得到下面的例子正常工作。

回答

7
SELECT id, name, last_reply, replies 
FROM (
     SELECT topic_id, MAX(date) AS last_reply, COUNT(*) AS replies 
     FROM wp_pod_tbl_forum 
     GROUP BY 
       topic_id 
     ) r 
JOIN wp_pod_tbl_forum t 
ON  t.topic_id = 0 
     AND t.id = r.topic_id 
UNION ALL 
SELECT id, name, date, 0 
FROM wp_pod_tbl_forum t 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM wp_pod_tbl_forum r 
     WHERE r.topic_id = t.id 
     ) 
     AND t.topic_id = 0 
ORDER BY 
     date DESC 
LIMIT 0, 20 

如果你的表是MyISAMid不是PRIMARY KEY,你需要在(topic_id, id)創建複合ondex。

如果你的表是InnoDBidPRIMARY KEY,只是(topic_id)指數會做(id將被隱式添加到索引)。

更新

這個查詢很可能會更加有效,前提是你必須在(topic_id, id)(date, id)指標:

看到這篇文章在我的博客的性能細節:

該查詢在30 ms完成上的100,000行採樣數據:

SELECT id, name, last_reply, 
     (
     SELECT COUNT(*) 
     FROM wp_pod_tbl_forum fc 
     WHERE fc.topic_id = fl.topic_id 
     ) AS replies 
FROM (
     SELECT topic_id, date AS last_reply 
     FROM wp_pod_tbl_forum fo 
     WHERE id = (
       SELECT id 
       FROM wp_pod_tbl_forum fp 
       WHERE fp.topic_id = fo.topic_id 
       ORDER BY 
         fp.date DESC, fp.id DESC 
       LIMIT 1 
       ) 
       AND fo.topic_id <> 0 
     ORDER BY 
       fo.date DESC, fo.id DESC 
     LIMIT 20 
     ) fl 
JOIN wp_pod_tbl_forum ft 
ON  ft.id = fl.topic_id 
UNION ALL 
SELECT id, name, date, 0 
FROM wp_pod_tbl_forum t 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM wp_pod_tbl_forum r 
     WHERE r.topic_id = t.id 
     ) 
     AND t.topic_id = 0 
ORDER BY 
     last_reply DESC, id DESC 
LIMIT 20 

兩個指數所需要的這個查詢是有效的。

如果你的表是InnoDBidPRIMARY KEY,那麼你可以從上面的indexes省略ID。

+0

字段列表中的列'date'不明確..? – Matt 2009-07-07 12:46:07

1

您可能希望將其分解爲一組子查詢(作爲內部查詢)。我需要的模式,以真正發揮,但如果你

SELECT t.id, t.name, MAX(COALESCE(r.date, t.date)) AS date, COUNT(r.id) AS replies 
FROM (
    SELECT (id, name, date) 
    FROM wp_pod_tbl_forum 
    WHERE topic_id = 0 
) as t 
LEFT OUTER JOIN 
    wp_pod_tbl_forum r 
WHERE 
    r.topic_id = t.id 
GROUP BY 
    t.id 
ORDER BY 
    date DESC LIMIT 0,20; 

,可能有助於加快速度一點點,它甚至可能不是最好的答案(可能存在誤差)。

有很多方法可以做到這一點,但在執行SQL調整時要儘可能減少每個集合,這是最重要的事情。

相關問題