我确信我必须做一些愚蠢的事情,但通常情况下我无法弄清楚它是什么。
我正在尝试运行此查询:
SELECT `f`.`FrenchWord`, `f`.`Pronunciation`, `e`.`EnglishWord`
FROM (`FrenchWords` f)
INNER JOIN `FrenchEnglishMappings` m ON `m`.`FrenchForeignKey`=`f`.`id`
INNER JOIN `EnglishWords` e ON `e`.`id`=`m`.`EnglishForeignKey`
WHERE `f`.`Pronunciation` = '[whatever]';
当我运行它时,发生的事情对我来说似乎很奇怪。我得到的查询结果很好,2行约0.002秒。
但是,我的CPU也出现了大幅增长,SHOW PROCESSLIST
显示了该查询的两个相同进程,状态为'复制到磁盘上的tmp表'。这些似乎一直无休止地运行,直到我杀死它们或系统冻结。
所涉及的表都不大 - 每行数在100k到600k之间。 tmp_table_size
和max_heap_table_size
均为16777216。
编辑:EXPLAIN
在声明中给出:
+编辑将发音的keylen缩小为112
+----+-------------+-------+--------+-------------------------------------------------------------+-----------------+---------+----------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------------------------------------------------+-----------------+---------+----------------------------+------+----------------------------------------------+
| 1 | SIMPLE | f | ref | PRIMARY,Pronunciation | Pronunciation | 112 | const | 2 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | m | ref | tmpindex,CombinedIndex,FrenchForeignKey,EnglishForeignKey | tmpindex | 4 | dict.f.id | 1 | Using index |
| 1 | SIMPLE | e | eq_ref | PRIMARY,id | PRIMARY | 4 | dict.m.EnglishForeignKey | 1 | |
+----+-------------+-------+--------+-------------------------------------------------------------+-----------------+---------+----------------------------+------+----------------------------------------------+
如果有人能够指出导致这种情况的原因,我将不胜感激。 我真正不理解的是MySQL正在做什么 - 当然,如果查询完成,那么它不需要做任何其他事情吗?
感谢所有回复。我从所有人那里学到了一些东西。遵循nrathaus的建议,这个查询大大加快了。我在FrenchWords中添加了一个发音哈希二进制(16)列,其中包含unhex(md5(发音))。这是使用16的keylen索引(对于发音中的varchar索引为600+),现在查询速度要快得多。
答案 0 :(得分:1)
您滥用GROUP BY
。除非您的MAX(something)
子句中还包含COUNT(*)
或SELECT
等摘要功能,否则此子句完全没有意义。
尝试删除GROUP BY
并查看是否有帮助。
目前尚不清楚您要对GROUP BY
做些什么。但是,如果您尝试对结果集进行重复数据删除,则可以尝试SELECT DISTINCT
。
答案 1 :(得分:1)
正如EXPLAIN所说,你的密钥大小是巨大的:602,这需要MySQL写下数据。
你需要减少(大大)keylen,我相信建议低于128。
我建议你创建一个名为MD5_FrenchWord的列,它将包含FrenchWord的MD5值。然后将此列用于GROUP BY。这假设您在分组时而不是实际值
时寻找相似之处答案 2 :(得分:1)
进一步研究这个问题,看起来你可能会从一些复合指数中受益。
首先,您能确保您的表格声明在尽可能多的列中有NOT NULL
吗?
其次,您正在从Frenchwords表中检索发音,FrenchWord和id,因此请在该表上尝试此复合索引。然后,您的查询将能够直接从索引中获取所需内容,从而节省了大量磁盘io。请注意,在复合索引声明中首先提到发音,因为这是您要搜索的值。这允许MySQL对索引进行查找,并直接从索引中获取所需的其他信息,而不会反击到表本身。
(Pronunciation, FrenchWord, id)
您正在通过ID查找英文字样的英文字样。因此,同样的推理可以适用于这个复合指数。
(id, Englishword)
最后,一旦你使用SELECT DISTINCT
,我无法判断你的ORDER BY是什么。你可能会尝试摆脱它。但它可能没什么区别。
试一试。如果您的MySQL服务器在进行这些更改后仍在抖动,则会出现某种配置问题。