我在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 |
+------------+
有人可以解释一下这种行为吗?
答案 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)
您可以通过两种主要方式提高查询效果
对于索引,在要搜索匹配项的列上添加索引: 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