2013-02-11 88 views
0

我正在创建一个论坛,需要一点反馈。我一直在编程很长一段时间,但我对MySQL很熟悉,并且想知道我是否正确地做了这件事。优化我的MySQL查询

这是我用来输出所选论坛的thr主题索引的查询。我试图在单个查询中收集所有信息,而不是仅收集主题信息,然后在每个循环的每个循环中收集一次帖子和成员信息,总计达到35个单独查询(每个主题一个 )。明白了吗?

基本上,它的工作原理。它有点慢(大约1秒),即使只有300-400个话题。

我用分析,并聚集了最耗时的操作是: 复制到tmp下表:0.538037 发送数据:0.206218 复制到组表:0.137549

编辑: 查询会每次有人进入页面时运行一次(通过网站活动判断,每小时约200-300次)。我打算每次检索大约4000-5000行。

我的问题是:这是最好的方法吗?有什么我可以做,以优化此查询?或者我会更好地在循环内部执行很多较小的查询吗?

$user_id: id of the user 
$forum_id: id of the selected forum 


SELECT 
    # Topic records 
    `topics`.*, 

    # First Post 
    GROUP_CONCAT(`posts`.`id`) AS `post_id`, # All post ids 
    `posts`.`post` AS `post_first_msg`, 
    `posts`.`date` AS `post_first_date`, 
    `posts`.`member` AS `post_first_member`, 

    # First member 
    `members`.`id` AS `member_id`, 
    `members`.`username` AS member_username, 

    # Returns last 3 members' id 
    SUBSTRING_INDEX(
    GROUP_CONCAT(`members`.`id` ORDER BY `posts`.`date` DESC SEPARATOR '\\\\'), '\\\\', 3 
) AS member_last_id, 

    # Returns last 3 members' username 
    SUBSTRING_INDEX(
    GROUP_CONCAT(`members`.`username` ORDER BY `posts`.`date` DESC SEPARATOR '\\\\'), '\\\\', 3 
) AS member_last_username, 

    # Get last viewed topic id 
    `member_topic_lastview`.`lastview` AS `lastview` 

FROM 
    `topics` 

# Returns the `posts` table in ASC order 
JOIN (
    SELECT * 
    FROM `posts` 
    ORDER BY `posts`.`date` ASC 
) AS `posts` ON `posts`.`topic` = `topics`.`id` 

# Member table, only the columns needed 
JOIN (
    SELECT 
    `members`.`id`, 
    `members`.`username` 
FROM `members` 
) AS `members` ON `members`.`id` = `posts`.`member` 

# Forum table, containing the forum info 
LEFT JOIN `forum` ON `forum`.`id` = `topics`.`forum` 

# Table containing the latest viewed post id of each topic 
LEFT JOIN (
    SELECT * 
    FROM `member_topic_lastview` 
    WHERE `member_topic_lastview`.`member` = '$user_id' 
) AS `member_topic_lastview` ON `member_topic_lastview`.`topic` = `topics`.`id` 

WHERE 
    `forum` > $forum_id 

GROUP BY 
    `topics`.`id` 

ORDER BY 
    `topics`.`sticky` DESC, 
    MAX(`posts`.`date`) DESC 

LIMIT 35 

非常感谢!

+0

如何经常干这种查询需要运行?您打算查询多少数据? – tadman 2013-02-11 22:25:02

+1

你在各种表格上有什么样的索引? – Melanie 2013-02-11 22:29:00

+0

每次有人进入该页面时,该查询将会运行一次(通过网站活动判断,每小时约200-300次)。我打算每次检索大约4000-5000行。如果你喜欢,我可以找出尺寸。 – Tom 2013-02-11 22:30:19

回答

2

首先要做的是看看你的解释计划并发布。另一个突出的地方是你并不想做很多子查询。

只给一开始,看着你的第一个加入

FROM 
    `topics` 

# Returns the `posts` table in ASC order 
JOIN (
    SELECT * 
    FROM `posts` 
    ORDER BY `posts`.`date` ASC 
) AS `posts` ON `posts`.`topic` = `topics`.`id` 

这可能将是更快,如果你只是把它写这样的:

FROM 
    `topics` 

# Returns the `posts` table in ASC order 
JOIN `posts` ON `posts`.`topic` = `topics`.`id` 
+1

谢谢。但我需要按日期顺序检索帖子表,这是我知道如何的唯一方法。 – Tom 2013-02-11 22:33:13

+0

然后在查询的最后端执行'ORDER BY posts.date ASC'? – Patashu 2013-02-11 22:37:58

+0

@TomMcPadden - 您最好的选择是获取您想要的所有数据的原始列表,然后在另一个查询中进行换行。如果您可以将一些示例表格和数据发布到http://www.sqlfiddle.com以及预期结果中,我可以给您更好的建议。 – 2013-02-11 22:40:08