2009-07-07 127 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调整时要尽可能减少每个集合,这是最重要的事情。

相关问题