[英]Optimize MySQL query to avoid “Using where; Using temporary; Using filesort”
I built a custom forum for my site using MySQL. 我使用MySQL为我的网站建立了一个自定义论坛。 The listing page is essentially a table with the following columns: Topic , Last Updated , and # Replies . 列表页面本质上是一个包含以下列的表: 主题 , 上次更新和#Reslies 。
The DB table has the following columns: DB表包含以下列:
id
name
body
date
topic_id
email
A topic has the topic_id of "0", and replies have the topic_id of their parent topic. 主题的topic_id为“0”,并且回复具有其父主题的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;
There are about 2,100 total items in this table, and queries usually take a whopping 6 seconds. 此表中共有约2,100项,查询通常需要6秒钟。 I added an INDEX to the "topic_id" column, but that didn't help much. 我在“topic_id”列中添加了一个INDEX,但这没有多大帮助。 Are there any ways of speeding up this query w/out doing significant restructuring? 有没有办法加速这个查询而不进行重大重组?
EDIT : not quite working yet. 编辑 :还没有完成工作。 I can't seem to get the examples below to work properly. 我似乎无法让下面的例子正常工作。
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
If your table is MyISAM
or id
is not a PRIMARY KEY
, you need to create a composite ondex on (topic_id, id)
. 如果您的表是MyISAM
或者id
不是PRIMARY KEY
,则需要在(topic_id, id)
上创建复合索引。
If your table is InnoDB
and id
is a PRIMARY KEY
, an index just on (topic_id)
will do ( id
will be implicitly added to the index). 如果你的表是InnoDB
并且id
是一个PRIMARY KEY
,那么只有on (topic_id)
的索引会做( id
将被隐式添加到索引中)。
Update 更新
This query will most probably be even more efficient, provided that you have indexes on (topic_id, id)
and (date, id)
: 只要你有(topic_id, id)
和(date, id)
索引,这个查询很可能会更有效:
See this article in my blog for performance details: 有关性能详情,请参阅我的博客中的这篇文章
This query completes in 30 ms
on a 100,000
rows sample data: 对于100,000
行样本数据,此查询在30 ms
完成:
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
Both indexes are required for this query to be efficient. 这个查询都需要这两个索引才能有效。
If your table is InnoDB
and id
is a PRIMARY KEY
, then you can omit id from the indexes
above. 如果您的表是InnoDB
且 id
是PRIMARY KEY
,那么您可以从上面的indexes
省略id。
You may want to break it up into a set of subqueries (as inner queries). 您可能希望将其分解为一组子查询(作为内部查询)。 I'd need the schema to really play, but if you 我需要架构真正发挥,但如果你
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;
that may help speed it up a little, it may not even be the best answer (errors may exist). 这可能有助于加快一点,甚至可能不是最佳答案(可能存在错误)。
There are tons of ways to do it, but the most important thing to do when SQL tuning is to reduce each set as much as possible before performing an operation. 有很多方法可以做到这一点,但是当SQL调优是在执行操作之前尽可能地减少每个集合时最重要的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.