使SQL查询更有效

时间:2012-09-16 17:24:06

标签: php mysql

我有一个有效的查询,但它至少需要3秒才能运行,所以我认为它可能会更快。它用于填充新线程列表,并显示每个线程中有多少未读帖子。我在将查询字符串放入$db->query_read()之前生成查询字符串。为了仅从有效论坛中获取结果,$ids是最多50个以逗号分隔的值的字符串。

userthreadviews表已存在1周,其中大约有9,500行。我不确定是否需要设置一个cron作业来定期清除超过一周的线程视图,或者我是否会好好让它成长。

以下是目前的查询:

SELECT 
    `thread`.`title` AS 'r_title', 
    `thread`.`threadid` AS 'r_threadid', 
    `thread`.`forumid` AS 'r_forumid', 
    `thread`.`lastposter` AS 'r_lastposter', 
    `thread`.`lastposterid` AS 'r_lastposterid', 
    `forum`.`title` AS 'f_title', 
    `thread`.`replycount` AS 'r_replycount', 
    `thread`.`lastpost` AS 'r_lastpost', 
    `userthreadviews`.`replycount` AS 'u_replycount', 
    `userthreadviews`.`id` AS 'u_id',
    `thread`.`postusername` AS 'r_postusername', 
    `thread`.`postuserid` AS 'r_postuserid' 
FROM 
    `thread` 
INNER JOIN 
    `forum` 
    ON (`thread`.`forumid` = `forum`.`forumid`) 
LEFT JOIN 
    (`userthreadviews`) 
    ON (`thread`.`threadid` = `userthreadviews`.`threadid` 
    AND `userthreadviews`.`userid`=$userid) 
WHERE 
    `thread`.`forumid` IN($ids) 
    AND `thread`.`visible`=1 
    AND `thread`.`lastpost`> time() - 604800
ORDER BY `thread`.`lastpost` DESC LIMIT 0, 30

加入post表的另一个查询(仅显示用户发布的帖子)的速度实际上是原来的两倍,所以我认为这里必须有一些可以改变以加速它的东西。有人可以提供一些建议吗?

编辑:对不起,我已将EXPLAIN放在备用查询的前面。这是正确的输出: 如同请求,这是EXPLAIN SELECT生成的输出: EXPLAINS Query

4 个答案:

答案 0 :(得分:2)

查看mysql explain声明。它为您提供查询的执行计划。

了解该计划后,您可以检查您是否获得了计划中涉及的字段的索引。如果没有,请创建它们。

也许该计划揭示了如何以另一种方式编写查询的详细信息,以便更加优化查询。

答案 1 :(得分:1)

如果没有编入索引,请尝试索引表forumid

答案 2 :(得分:1)

要在连接/ where上没有索引(在解释时使用key = NULL),这就是你的查询速度慢的原因。您应该以这样的方式索引它们:

CREATE INDEX thread_forumid_index ON thread(forumid);
CREATE INDEX userthreadviews_forumid_index ON userthreadviews(forumid);

文档here

答案 3 :(得分:0)

建议:

  • 将条件从WHERE子句移动到JOIN子句
  • 在其他JOIN
  • 之前使用条件放置JOIN
  • 确保你有正确的索引,并且它们正在查询中使用(创建你需要的索引......太多的索引可能差得太少)

以下是我对查询的建议:

SELECT 
    `thread`.`title` AS 'r_title',
    `thread`.`threadid` AS 'r_threadid',
    `thread`.`forumid` AS 'r_forumid',
    `thread`.`lastposter` AS 'r_lastposter',
    `thread`.`lastposterid` AS 'r_lastposterid',
    `forum`.`title` AS 'f_title',
    `thread`.`replycount` AS 'r_replycount',
    `thread`.`lastpost` AS 'r_lastpost',
    `userthreadviews`.`replycount` AS 'u_replycount',
    `userthreadviews`.`id` AS 'u_id',
    `thread`.`postusername` AS 'r_postusername',
    `thread`.`postuserid` AS 'r_postuserid' 
FROM
    `thread` 
    INNER JOIN (`forum`)
        ON ((`thread`.`visible` = 1)
        AND (`thread`.`lastpost` > $time)
        AND (`thread`.`forumid` IN ($ids))
        AND (`thread`.`forumid` = `forum`.`forumid`))
    LEFT JOIN (`userthreadviews`)
        ON ((`thread`.`threadid` = `userthreadviews`.`threadid`)
        AND (`userthreadviews`.`userid` = $userid))
ORDER BY
    `thread`.`lastpost` DESC
LIMIT
    0, 30

这些是被编入索引的好候选人:

- `forum`.`forumid`
- `userthreadviews`.`threadid`
- `userthreadviews`.`userid`
- `thread`.`forumid`
- `thread`.`threadid`
- `thread`.`visible`
- `thread`.`lastpost`

看来你已经拥有了很多索引......所以,请确保保留你真正需要的索引并删除无用的索引。