Here is my first slow query:
# Query_time: 25 Lock_time: 0 Rows_sent: 8 Rows_examined: 149647
SELECT `t`.*, COUNT(`p`.`id`) AS `postCount`, MAX(`p`.`createStamp`) AS `createStamp`
FROM `ow_forum_topic` AS `t`
LEFT JOIN `ow_forum_group` AS `g`
ON (`t`.`groupId` = `g`.`id`)
LEFT JOIN `ow_forum_section` AS `s`
ON (`s`.`id` = `g`.`sectionId`)
LEFT JOIN `ow_forum_post` AS `p`
ON (`t`.`id` = `p`.`topicId`)
WHERE `s`.`isHidden` = 0
GROUP BY `p`.`topicId`
ORDER BY `createStamp` DESC
LIMIT 8;
This is triggered on my index page, where I set it to show the latest 8 topics. As you can see I have 149.647 posts on my site, and here you can see the query is extremely bad written in trying to get all the posts on my site. There should be at least a where clause by limiting the posts to some kind of date limit to bring this back to about 100 posts at most.
Here is my optimized query, where I ask for the posts from at least 30 days old:
SELECT `t` . * , COUNT( `p`.`id` ) AS `postCount` , MAX( `p`.`createStamp` ) AS `createStamp`
FROM `ow_forum_topic` AS `t`
LEFT JOIN `ow_forum_group` AS `g` ON ( `t`.`groupId` = `g`.`id` )
LEFT JOIN `ow_forum_section` AS `s` ON ( `s`.`id` = `g`.`sectionId` )
LEFT JOIN `ow_forum_post` AS `p` ON ( `t`.`id` = `p`.`topicId` )
WHERE `s`.`isHidden` =0
AND createStamp > UNIX_TIMESTAMP( ) -2592000
GROUP BY `p`.`topicId`
ORDER BY `createStamp` DESC
LIMIT 8
When running this query in mysql it now took about 1.5 seconds instead of the original 12.8 seconds! So this is already a huge win :).
I also added an index to the "createStamp" column to even improve more the performance:
ALTER TABLE `ow_forum_post` ADD INDEX `timestamp_idx` ( `createStamp` )
And WOW now the query only takes about 0.012 seconds. So this is the biggest win already.
With the big index, the old query still takes about 10 seconds, so that is not the biggest win.
So I went down digging the code to find the query.
The problematic file is here:
/var/www/html/ow_plugins/forum/bol/topic_dao.php
In this file you can see:
public function findLastTopicList( $limit, $excludeGroupIdList = null )
{
$postDao = FORUM_BOL_PostDao::getInstance();
$groupDao = FORUM_BOL_GroupDao::getInstance();
$sectionDao = FORUM_BOL_SectionDao::getInstance();
$excludeCond = $excludeGroupIdList ? ' AND `g`.`id` NOT IN ('.implode(',', $excludeGroupIdList).') = 1' : '';
$query = "
SELECT `t`.*, COUNT(`p`.`id`) AS `postCount`, MAX(`p`.`createStamp`) AS `createStamp`
FROM `" . $this->getTableName() . "` AS `t`
LEFT JOIN `" . $groupDao->getTableName() . "` AS `g`
ON (`t`.`groupId` = `g`.`id`)
LEFT JOIN `" . $sectionDao->getTableName() . "` AS `s`
ON (`s`.`id` = `g`.`sectionId`)
LEFT JOIN `" . $postDao->getTableName() . "` AS `p`
ON (`t`.`id` = `p`.`topicId`)
WHERE `s`.`isHidden` = 0 ".$excludeCond."
GROUP BY `p`.`topicId`
ORDER BY `createStamp` DESC
LIMIT ?
";
return $this->dbo->queryForList($query, array($limit));
}
Now update this with:
public function findLastTopicList( $limit, $excludeGroupIdList = null )
{
$postDao = FORUM_BOL_PostDao::getInstance();
$groupDao = FORUM_BOL_GroupDao::getInstance();
$sectionDao = FORUM_BOL_SectionDao::getInstance();
$excludeCond = $excludeGroupIdList ? ' AND `g`.`id` NOT IN ('.implode(',', $excludeGroupIdList).') = 1' : '';
$query = "
SELECT `t`.*, COUNT(`p`.`id`) AS `postCount`, MAX(`p`.`createStamp`) AS `createStamp`
FROM `" . $this->getTableName() . "` AS `t`
LEFT JOIN `" . $groupDao->getTableName() . "` AS `g`
ON (`t`.`groupId` = `g`.`id`)
LEFT JOIN `" . $sectionDao->getTableName() . "` AS `s`
ON (`s`.`id` = `g`.`sectionId`)
LEFT JOIN `" . $postDao->getTableName() . "` AS `p`
ON (`t`.`id` = `p`.`topicId`)
WHERE `s`.`isHidden` = 0 ".$excludeCond."
and createStamp > UNIX_TIMESTAMP()-
2592000
GROUP BY `p`.`topicId`
ORDER BY `createStamp` DESC
LIMIT ?
";
return $this->dbo->queryForList($query, array($limit));
}
Wow, wat a big boost this gives! :).