此查询运行时间超过12秒,即使所有表都相对较小 - 约为2 000行。
SELECT attr_73206_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ o
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id
INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_
ORDER BY o.id_order
) AS o GROUP BY o.id_field
) AS o ON f1.id = o.id_field
两个表都有字段id
作为主键。此外,id_field
,id_order
,attr_73206_
和master_slave
中的所有字段都已编入索引。至于这个查询的逻辑,总的来说它是主要的细节类型。表object_73130_
是主表,表object_73200_
是详细表。它们由master_slave
表链接。 object_73101_
是一个临时表,用于通过其id获取字段attr_73206_
的实际值。对于主表中的每一行,查询从其详细信息表的第一行返回一个字段。首先,查询有另一种看法,但是在stackoverflow中,我被建议使用这个更优化的结构(而不是之前使用的子查询,顺便说一下,查询开始运行得更快)。我观察到第一个JOIN
块中的子查询运行速度非常快,但返回的行数与主主表中的行数相当。无论如何,我不知道如何优化它。我只是想知道为什么一个简单的快速连接会导致很多麻烦。哦,主要的观察是,如果我从查询中删除ad-hoc object_73101_
只返回一个id,而不是一个真正的值,那么查询就像flash一样快。所以,所有注意力应该集中在查询的这一部分
INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_
为什么它会使整个查询变得非常缓慢?
修改
以这种方式运行超快
SELECT t0.attr_73102_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, attr_73206_ FROM object_73200_ o
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id
ORDER BY o.id_order
) AS o GROUP BY o.id_field
) AS o ON f1.id = o.id_field
LEFT JOIN object_73101_ t0 ON t0.id = o.attr_73206_
所以,你可以看到,我只是将add-hoc连接放在子查询之外。但是,问题是,子查询是自动创建的,我可以访问创建它的algo那部分,我可以修改这个算法,而且我无法访问构建整个查询的algo部分,所以我唯一能做的就是以某种方式修复子查询。无论如何,我仍然无法理解为什么子查询中的INNER JOIN
会使整个查询减慢数百次。
修改
每个表具有不同别名的新版本查询。这对性能没有影响:
SELECT attr_73206_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ a
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = a.id
INNER JOIN object_73101_ t0 ON t0.id = a.attr_73206_
ORDER BY a.id_order
) AS b GROUP BY b.id_field
) AS c ON f1.id = c.id_field
修改
这是EXPLAIN
命令的结果:
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ROWS | Extra |
| 1 | PRIMARY | f1 | INDEX | NULL | PRIMARY | 4 | 1570 | USING INDEX
| 1 | PRIMARY | derived2| ALL | NULL | NULL | NULL | 1564 |
| 2 | DERIVED | derived3| ALL | NULL | NULL | NULL | 1575 | USING TEMPORARY; USING filesort
| 3 | DERIVED | m | RANGE | id_object,id_master,..| id_object | 4 | 1356 | USING WHERE; USING TEMPORARY; USING filesort
| 3 | DERIVED | a | eq_ref | PRIMARY,attr_73206_ | PRIMARY | 4 | 1 |
| 3 | DERIVED | t0 | eq_ref | PRIMARY | PRIMARY | 4 | 1 |
这有什么问题?
修改
以下是“超级快速”查询的EXPLAIN
命令的结果
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ROWS | Extra
| 1 | PRIMARY | f1 | INDEX | NULL | PRIMARY | 4 | 1570 | USING INDEX
| 1 | PRIMARY | derived2| ALL | NULL | NULL | NULL | 1570 |
| 1 | PRIMARY | t0 | eq_ref| PRIMARY | PRIMARY | 4 | 1 |
| 2 | DERIVED | derived3| ALL | NULL | NULL | NULL | 1581 | USING TEMPORARY; USING filesort
| 3 | DERIVED | m | RANGE | id_object,id_master,| id_bject | 4 | 1356 | USING WHERE; USING TEMPORARY; USING filesort
| 3 | DERIVED | a | eq_ref | PRIMARY | PRIMARY | 4 | 1 |
CLOSED
我将使用我自己的“超快速”查询,我在上面提到过。我认为不可能再优化它了。
答案 0 :(得分:1)
在不知道数据/查询的确切性质的情况下,我看到了几件事情:
MySQL在处理子选择方面非常糟糕,因为它需要创建派生表。实际上,某些版本的MySQL在使用子选择时也会忽略索引。通常情况下,最好使用JOIN而不是子选择,但如果您需要使用子选择,最好使该子选择尽可能精简。
除非你有一个非常具体的理由将ORDER BY放在子选择中,否则将它移到“主”查询部分可能是一个好主意,因为结果集可能更小(允许更快的排序)。
所有这一切,我试图使用JOIN逻辑重新编写您的查询,但我想知道最终值(attr_73102_)来自哪个表?它是子选择的结果,还是来自表object_73130_?如果它来自子选择,那么我不明白你为什么要打扰原来的LEFT JOIN,因为你只会从子选择返回值列表,而对于任何不匹配的行都返回NULL来自object_73130 _。
无论如何,不知道这个答案,我认为下面的查询可能在语法上是等价的:
SELECT t0.attr_73102_ AS attr_73270_
FROM object_73130_ f1
LEFT JOIN (object_73200_ o
INNER JOIN master_slave m ON m.id_slave_field = o.id
INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_)
ON f1.id = o.id_field
WHERE m.id_object IN (73130,73290)
AND m.id_master IN (73200,73354)
GROUP BY o.id_field
ORDER BY o.id_order;