优化MySQL查询以避免“使用where;使用临时;使用filesort”
问题描述:
我使用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,但没有多大帮助。有没有什么方法可以加速这个查询,而不用做重大的重组?
编辑:还没有工作。我似乎无法得到下面的例子正常工作。
答
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
如果你的表是MyISAM
或id
不是PRIMARY KEY
,你需要在(topic_id, id)
创建复合ondex。
如果你的表是InnoDB
和id
是PRIMARY 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
两个指数所需要的这个查询是有效的。
如果你的表是InnoDB
和id
是PRIMARY KEY
,那么你可以从上面的indexes
省略ID。
答
您可能希望将其分解为一组子查询(作为内部查询)。我需要的模式,以真正发挥,但如果你
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调整时要尽可能减少每个集合,这是最重要的事情。
字段列表中的列'date'不明确..? – Matt 2009-07-07 12:46:07