小编典典

JOIN与WHERE:为什么两个获得相同结果的查询表现出3-4个数量级的性能差异?

sql

这是一个问题,为方便起见重复:

如果我有此数据:

code1 code2
  1    10       <-- Desired (1 appears more than once)
  1    11       <-- Desired (1 appears more than once)
  2    20
  3    30       <-- Desired (3 appears more than once)
  3    31       <-- Desired (3 appears more than once)
  4    40
  5    50

…而且我想编写一个 单一的SQL查询, 其结果如下:

code1 code2
  1    10       <-- This result appears because 1 appears more than once above
  1    11       <-- This result appears because 1 appears more than once above
  3    30       <-- This result appears because 3 appears more than once above
  3    31       <-- This result appears because 3 appears more than once above

(即,一个SQL查询返回的所有行中该code1列中的任何数据均显示不止一次)

我该怎么做?

我收到了两个可能的SQL查询的答案,两个查询都可以正常工作。

成功的SQL#1:

SELECT code1, code2
FROM myTable
WHERE code1 IN 
    (SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1)

成功的SQL#2:

SELECT t.code1, code2
FROM myTable t
  INNER JOIN
    (SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1)
     s on s.code1 = t.code1

正如我在答案下方的评论中所描述的:

myTable大约有30000行,只有大约400个重复的组,每个重复的组几乎总是只有2个条目。在高端工作站上运行的MySQL实例上,
SQL#1 大约需要30分钟才能执行,而 SQL#2 需要一秒钟的时间。

这是上述两个查询之间的 性能差异三到四个数量级

令我感到困扰的是,在查询中,为什么我的用例中一个要比另一个好三个数量级,这对我来说并不是立即显而易见的。

我想对SQL执行的内部有更好的了解,这个特殊的示例非常适合于此。

我的问题是: 为什么 在我的用例 中,SQL#2的性能要比SQL#1快5,000倍


阅读 182

收藏
2021-03-23

共1个答案

小编典典

MySQL在优化涉及相关子查询或子选择的查询方面存在已知问题。在5.6.5版之前,它不会具体化子查询,但是将具体化联接中使用的派生表。

从本质上讲,这意味着当您使用联接时,第一次遇到子查询时,MySQL将执行以下操作:

SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1

并将结果保存在临时表中(将其哈希处理以加快查找速度),然后myTable针对临时表中的每个值进行查找,以查看代码是否存在。

但是,由于当您使用IN子查询时,该子查询并未实现,而是被重写为:

SELECT t1.code1, t1.code2
FROM myTable t1
WHERE EXISTS
    (   SELECT t2.code1 
        FROM myTable t2
        WHERE t2.Code1 = t1.Code1
        GROUP BY t2.code1 
        HAVING COUNT(t2.code1) > 1
    )

这意味着,对于codein中的每个myTable,它将再次运行子查询。当您的外部查询非常狭窄时,哪种方法比较好,因为只运行几次子查询比对所有值运行它并将结果存储在临时表中更为有效,但是当您的外部查询很宽时,它会得到结果在内部查询中执行了很多次,这就是性能差异的所在。

因此,对于您的行数,您无需运行子查询约30,000次,而是运行一次,然后在仅包含400行的哈希临时表中查找约30,000行。这将导致如此巨大的性能差异。

在线文档中的这篇文章更深入地解释了子查询优化。

2021-03-23