两个相似的SQL查询之间的巨大性能差异

时间:2014-10-12 08:56:25

标签: mysql sql

我有两个提供相同输出的SQL查询。 我的第一个直觉就是使用它:

SELECT * FROM performance_dev.report_golden_results 
where id IN (SELECT max(id) as 'id' from  performance_dev.report_golden_results 
group by platform_id, release_id, configuration_id)

现在,这需要70秒才能完成!

寻找另一种解决方案我尝试了类似的东西:

SELECT * FROM performance_dev.report_golden_results e 
join (SELECT max(id) as 'id' 
from performance_dev.report_golden_results 
group by platform_id, release_id, configuration_id) s 
ON s.id = e.id;

令人惊讶的是,这需要0.05秒才能完成!!!

为什么这两者如此不同?

谢谢!

2 个答案:

答案 0 :(得分:0)

可能导致时间滞后的第一件事是MySQL使用“半连接”策略进行子查询。半连接包括以下步骤:

  

如果子查询符合上述条件,MySQL会将其转换为a   半连接并根据这些策略进行基于成本的选择:

     

将子查询转换为连接,或使用表pullout并运行查询   作为子查询表和外部表之间的内部联接。表   pullout将一个表从子查询拉出到外部查询。

     

Duplicate Weedout:运行半连接,就好像它是一个连接并删除   使用临时表重复记录。

     

FirstMatch:扫描内部表格中的行组合和   有一个给定值组的多个实例,请选择一个   而不是归还他们。这种“快捷方式”扫描并消除   产生不必要的行。

     

LooseScan:使用启用单个索引的索引扫描子查询表   要从每个子查询的值组中选择的值。

     

将子查询实现为具有索引和使用的临时表   用于执行连接的临时表。该索引用于删除   重复。索引也可能稍后用于查找   将临时表与外表联系起来;如果没有,表格   扫描。

但是,明确加入会减少这些可能是原因的努力。

我希望它有所帮助!

答案 1 :(得分:0)

MySQL 不考虑第一个查询作为半连接优化的主题(MySQL 通过某种优化将半连接转换为经典连接:第一次匹配,重复淘汰......) 因此,将对第一个表进行全面扫描,并对外部选择生成的每一行评估子查询:因此性能不佳。

第二个是经典连接,在这种情况下会发生什么,MySQL 将计算派生查询的结果,然后仅将来自该查询的值与满足条件的第一个查询的值进行匹配,因此不需要完全扫描第一个表(我在这里假设 id 是一个索引列)。

现在的问题是为什么 MySQL 不考虑将第一个查询作为半连接优化的主题:答案记录在 MySQL https://dev.mysql.com/doc/refman/5.6/en/semijoins.html

In MySQL, a subquery must satisfy these criteria to be handled as a semijoin:

It must be an IN (or =ANY) subquery that appears at the top level of the WHERE or ON clause, possibly as a term in an AND expression. For example:

SELECT ...
FROM ot1, ...
WHERE (oe1, ...) IN (SELECT ie1, ... FROM it1, ... WHERE ...);
Here, ot_i and it_i represent tables in the outer and inner parts of the query, and oe_i and ie_i represent expressions that refer to columns in the outer and inner tables.

It must be a single SELECT without UNION constructs.

It must not contain a GROUP BY or HAVING clause.

It must not be implicitly grouped (it must contain no aggregate functions).

It must not have ORDER BY with LIMIT.

The STRAIGHT_JOIN modifier must not be present.

The number of outer and inner tables together must be less than the maximum number of tables permitted in a join.

您的子查询使用 GROUP BY,因此未应用半连接优化。