我試圖在我的網站的查詢中進行一些優化。我一直認爲,使用一個「JOIN」查詢比在php循環中放置幾個查詢更好,但是當我這樣做時,它真的很慢。加入查詢比使用php和MySQL循環查詢慢20倍
在循環中查詢的原始方法需要0.055s,新加入「加入」需要1.084s ..我應該使用哪種解決方案?有沒有辦法讓新查詢更快?也許另一個想法是用循環在mysql中創建一個過程?
這是情況:我有一個論壇,在論壇上的主題和主題的消息。爲了得到用戶名,我在用戶信息表中得到了用戶的id,如果這是肯定的,那麼它是註冊用戶,否則它是賓客表中的一個訪客。不知道這是不是一個好的建築,但我不能把客人和註冊會員放在同一張桌子上。
CREATE TABLE `topic` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`post_date` int(14) NOT NULL DEFAULT '0',
`last_answere_date` int(14) NOT NULL,
`author_name` varchar(50) NOT NULL DEFAULT '',
`title` varchar(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `msgs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`topic_id` int(10) unsigned NOT NULL DEFAULT '0',
`post_date` int(14) unsigned DEFAULT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `topic_id` (`topic_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nom` varchar(30) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `guests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
和我的兩個情況:
//Goal : get the list of 5 new topics or topic with new messages
//Methode query in loop
$timestart=microtime(true);
echo '<h3>Query in loop</h3>';
//Get the list of new topics
$reqTopic = $bdd->query('SELECT id,title,author_name,post_date FROM topic ORDER BY last_answere_date DESC LIMIT 0,5');
While($topic = $reqTopic->fetch())
{
//Get the last message
$reqMsgs = $bdd->prepare('SELECT count(*) as msgCount, user_id,post_date FROM msgs WHERE topic_id=? ORDER BY post_date DESC');
$reqMsgs->bindparam(1,$topic['id'],PDO::PARAM_INT);
$reqMsgs->execute();
$msg = $reqMsgs->fetch();
//IF the id is >0 then it's a registered member, else it's a guest
if($msg['user_id'] > 0)
$reqAuthor = $bdd->prepare('SELECT nom as name FROM users WHERE id=? LIMIT 0,1');
else
$reqAuthor = $bdd->prepare('SELECT name FROM guests WHERE id=? LIMIT 0,1');
$reqAuthor->bindparam(1,$msg['user_id'],PDO::PARAM_INT);
$reqAuthor->execute();
$author = $reqAuthor->fetch();
//Output
echo '<strong>'.$topic['title']. '</strong><br/>'
.'Author : '. $topic['author_name'] . ' | Date : '. date('d/m/Y H:i',$topic['post_date']) .'<br/>';
if($msg['msgCount'] > 0)
{
echo 'Last msg author : '. $author['name'] . ' | Date : '. date('d/m/Y H:i',$msg['post_date']) .'<br/>'
.'Nbr msgs : '.$msg['msgCount'].'<br/>';
}
echo '<br/>';
}
//End of script : get time
$timeend=microtime(true);
$time=$timeend-$timestart;
echo '<strong>'.number_format($time, 10) . ' sec</strong>';
//Methode Left join
$timestart=microtime(true);
echo '<h3>Left Join</h3>';
//The query
$reqTopic = $bdd->query('SELECT t.id,title,t.author_name,t.post_date, m.*, (SELECT COUNT(*) FROM msgs WHERE t.id=topic_id) as msgCount
FROM topic t
LEFT JOIN (
SELECT m.id,topic_id,post_date as mdate,user_id, IFNULL(u.nom,i.name) as name
FROM msgs m
LEFT JOIN users u ON u.id=m.user_id
LEFT JOIN guests i ON i.id=-m.user_id
GROUP BY topic_id
ORDER BY post_date DESC
) m
ON t.id=m.topic_id
GROUP BY t.id
ORDER BY last_answere_date DESC LIMIT 0,5');
While($topic = $reqTopic->fetch())
{
//Output
echo '<strong>'.$topic['title']. '</strong><br/>'
.'Author : '. $topic['author_name'] . ' | Date : '. date('d/m/Y H:i',$topic['post_date']) .'<br/>';
if($topic['msgCount'] > 0)
{
echo 'Last msg author : '. $topic['name'] . ' | Date : '. date('d/m/Y H:i',$topic['mdate']) .'<br/>'
.'Nbr msgs : '.$topic['msgCount'].'<br/>';
}
echo '<br/>';
}
//End of script : get time
$timeend=microtime(true);
$time=$timeend-$timestart;
echo '<strong>'.number_format($time, 10) . ' sec</strong>';
您的問題是什麼?這兩段代碼似乎做了非常不同的事情,這將解釋性能的差異。 –
兩者的輸出完全相同。我讀過很多次,這是不好的把查詢放在php循環中,但是當我試圖不這樣做時,這是非常慢的。那麼,是否有解決方案來優化第二個查詢,或者在這種情況下,第一個解決方案更好? – Alabate