简单的MySQL查询运行速度很慢

时间:2012-11-20 13:13:31

标签: mysql sql phpmyadmin

我在MySQL中发现了一些奇怪的(对我来说)行为。我有一个简单的查询:

SELECT CONVERT( `text`.`old_text` 
USING utf8 ) AS stext
FROM  `text` 
WHERE  `text`.`old_id` IN 
(    
 SELECT  `revision`.`rev_text_id`
 FROM  `revision` 
 WHERE  `revision`.`rev_id`
 IN 
  (    
  SELECT `page_latest`
  FROM  `page` 
  WHERE `page_id` = 108
  )
)

当我运行它时,phpmyadmin显示执行时间为77.0446秒。
但后来我换了

WHERE  `text`.`old_id` IN 

通过

WHERE  `text`.`old_id` = 

它的执行时间降至约0.001秒。此查询的结果

 SELECT  `revision`.`rev_text_id`
 FROM  `revision` 
 WHERE  `revision`.`rev_id`
 IN 
  (    
  SELECT `page_latest`
  FROM  `page` 
  WHERE `page_id` = 108
  )    

+------------+
|rev_text_id |
+------------+
|6506        |
+------------+

有人可以解释一下这种行为吗?

3 个答案:

答案 0 :(得分:2)

尝试在以下列中添加INDEX

ALTER TABLE `text` ADD INDEX idx_text (old_id);
ALTER TABLE `revision` ADD INDEX idx_revision (rev_text_id);

并执行以下查询

SELECT  DISTINCT CONVERT(a.`old_text` USING utf8 ) AS stext
FROM    `text` a
        INNER JOIN `revision` b
            ON a.`old_id` = b.`rev_text_id`
        INNER JOIN `page` c
            ON b.`rev_id` = c.`page_latest`
WHERE   c.`page_id` = 108

PS:您是否还可以运行以下查询并发布各自的结果?

DESC `text`;
DESC `revision`;
DESC `page`;

答案 1 :(得分:1)

MySQLDB循环遍历内部查询的每个结果,并将其与外部查询中的每个记录进行比较。 在第二个内部查询中;

   WHERE  `revision`.`rev_id`
   IN 
   ( SELECT `page_latest`
     FROM  `page` 
     WHERE `page_id` = 108

你绝对应该使用'='而不是IN,因为你选择了一个不同的记录,当你知道每次只返回一条记录时,循环结果没有意义

答案 2 :(得分:1)

您可以通过两种主要方式提高查询效果

  • 添加索引(如Kuya提到的)
  • 在可能的情况下摆脱子查询

对于索引,在要搜索匹配项的列上添加索引:    text.old_id,revision.rev_text_id& page.page_id

ALTER TABLE `text` ADD INDEX idx_text (old_id);
ALTER TABLE `revision` ADD INDEX idx_revision (rev_text_id);
ALTER TABLE `page` ADD INDEX idx_page (page_id);

您的下一个问题是嵌套子选择是您的查询执行计划的地狱。这是一个讨论JOIN vs Subquery的好主题。这是一篇关于如何从mySQL中get execution plan info的文章。

首先看一下执行计划可能会让人感到困惑,但是当你不得不关注查询优化时,它将成为你最好的朋友。

以下是仅使用连接的同一查询的示例(您可以使用内部或左侧并获得几乎相同的结果)。我没有你的表或数据,所以请原谅synax问题(我无法在你的环境中逐字验证代码,但它应该给你一个很好的起点)。

SELECT 
  CONVERT( `text`.`old_text` USING utf8 ) AS stext
  FROM  `text` 
  -- inner join only returns rows when it can find a 
  --    matching `revision`.`rev_text_id` row to `text`.`old_id`
  INNER JOIN `revision`  
  ON `text`.`old_id` = `revision`.`rev_text_id` 
  -- Inner Join only returns rows  when it can find a 
  --  matching `page_latest` row to `page_latest`
  INNER JOIN `page`
  ON `revision`.`rev_id` = `page`.`page_latest`
WHERE `page`.`page_id` = 108