我在 mysql 数据库上遇到过慢查询。数据库看起来像单词一样简单,而不是一组单词和相关的东西,如图像、录音、句子到单词。Bluehost 声称我有巨大的开销和缓慢的查询,需要对其进行优化。
有什么可以优化数据库的解决方案!检查每个表(关系)或大量使用的查询以改进这一点的典型步骤列表?
在 tmp/logs 中找到的示例查询
SELECT transcription FROM english_details WHERE translation_id = '2216'
SELECT recording FROM word_recordings_de WHERE translation_id = '3342'
SELECT english_sentences.sentence_id, english_sentences.sentence_eng,
english_sentences.sentence_pl,english_sent_recordings.recording
FROM english_sentences LEFT JOIN english_sent_recordings USING (sentence_id)
WHERE english_sentences.translation_id = '2239'
SELECT post_it FROM post_it WHERE user_id = '' AND translation_id = 10562 LIMIT 1
我考虑这是否是数据库、查询或两个多用户的问题。Bluehost 共享主机每月的 480 000 次会话(谷歌分析)数量是否很大?
更新 您是否认为使用以下命令为给定单词集加载单词的关键操作:
$arWordIds = $this->getWordsIds();
foreach($arWordIds as $wordId) {
switch($this->wordset_type) {
case WordSet::TYPE_BASIC:
$col->addItem(new Word($this->dbc, $wordId), $wordId);
break;
case WordSet::TYPE_DETAILED:
$col->addItem(new WordDetails($this->dbc, $wordId), $wordId);
break;
}
}
可能是问题吗?因为有一个查询词的 id,然后查询给定 id 的每个词(对于句子、录音等可能有几个独立的查询)?也许更好地做一个更大的查询,比如像 WHERE translation_id IN (id1,id2,id3,...) 这样的所有单词数据,许多连接在一次运行中返回 100 个单词的数据?
但是我怎样才能手动填充这个 Word 对象呢?因为我在 PHP 中有这个 Word 对象作为一些 DAO 对象,它们使用提供的 id 加载给定 Word 的数据。那么这种编程将比我认为的面向对象更适合一些过程编程。当我在一个请求中装载所有数据时(单词、句子、评论)?这甚至可以为多个 id 加载一个请求词,并为每个词加载多个相关句子吗?或图像?
更新 2 我在很多地方都有索引、唯一性等,其中一些我已经添加了它。主键无处不在。在 WHERE 子句中使用属性时添加的索引。当然,如果我忘记添加它,可能会缺少一些索引。
我一直在执行 **EXPLAIN SELECT ... ** 并尝试实现 ALL 以外的访问类型,例如 const、ref、eq_ref 或 system。
示例表:(我想数据库中有 > 50-100 个表)
CREATE TABLE `post_it` (
`post_it` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`translation_id` int(10) unsigned NOT NULL,
`text` tinytext NOT NULL,
`lang` varchar(5) NOT NULL DEFAULT 'plen',
PRIMARY KEY (`post_it`),
KEY `user_id` (`user_id`,`translation_id`)
) ENGINE=MyISAM AUTO_INCREMENT=235 DEFAULT CHARSET=utf8
我还替换了 Word 对象构造。到目前为止,Word 属性在访问时都会延迟加载。所以它处于循环中(例如列表中的 100 个单词),然后在 XML 中打印出每个属性导致 5-10 个查询以获取本地单词、外来单词、转录等。不,我添加到 Word 构造函数中急切预加载所有属性是 1to1,只有我懒加载的属性 1toN。现在我考虑这样的查询是否会比不加入的几个简单的更好:
SELECT nt.french_id, nt.article, n.french_word, ft.english_id, '-' AS 'english_article', en.english_word, p.part,
ed.transcription, ed.definition, r.recording
FROM translation ft
INNER JOIN translation_enfr nt ON nt.translation_id = ft.translation_id
INNER JOIN french n ON n.french_id = nt.french_id
INNER JOIN english en ON en.english_id = ft.english_id
INNER JOIN parts p ON p.part_id = ft.part_id
LEFT JOIN english_details ed ON ed.translation_id = ft.translation_id
LEFT JOIN word_recordings r ON r.translation_id = ft.translation_id
WHERE ft.translation_id = 3