1

我在 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        |
+------------+

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

4

3 回答 3

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`;
于 2012-11-20T13:17:54.873 回答
1

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

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

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

于 2012-11-20T13:21:25.187 回答
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获取执行计划信息的文章。

首先查看执行计划可能会令人困惑,但当您必须关注查询优化时,它将是您最好的朋友。

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

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
于 2012-11-20T13:27:58.993 回答