MySQL IN子句使用子选择与值列表

时间:2013-05-06 17:22:26

标签: mysql performance

我需要对某些相关数据进行两级过滤。第一个查询类似于:

SELECT t1.fk_id 
FROM t1 
LEFT JOIN t3 ON t3.fk_id = t1.fk_id
WHERE t1.field1 > 10 AND t3.field2 = Y

第二个查询针对具有相同fk_id字段的另一个表运行,看起来像

SELECT t2.fk_id, SUM(t2.field3) AS sum_3, SUM(t2.field_4) AS sum_4 
FROM t2 
WHERE fk_id IN (fk_values_from_query_1)
GROUP BY t2.fk_id
HAVING sum_3 > 1000

现在,我可以从我所知道的两种不同的方式运行 - 尽管我不依赖于任何一种方法,也不依赖其他方法。我可以将第一个查询作为SUB-SELECT嵌入到第二个查询中,从性能角度来看,我理解这是非常糟糕的。或者,我可以从查询1的结果中提取值,并将它们作为列表嵌入到查询2中(在我的应用程序代码中)。

这个问题的两个部分是:

  1. 上述两种查询结构之间是否存在性能差异?
  2. 是否有更好的方法来构建这两个查询?
  3. 基准

    我没有对此进行全面测试,但是根据我的数据运行了我的版本以及Barmar发布的版本。我的查询在大约4.23秒内运行,而Barmar的版本仅运行0.60秒。这是85%的改善!

1 个答案:

答案 0 :(得分:3)

您应该使用JOIN组合它们:

SELECT t2.fk_id, SUM(t2.field3) AS sum_3, SUM(t2.field_4) AS sum_4 
FROM t2
JOIN (SELECT distinct t1.fk_id
      FROM t1
      JOIN t2 ON t3.fk_id = t1.fk_id
      WHERE t1.field1 > 10 AND t3.field2 = 'Y') t4
ON t2.fk_id = t4.fk_id
GROUP BY t2.fk_id
HAVING sum_3 > 1000

我一直发现,与类似的连接相比,MySQL在WHERE col IN (subquery)查询上表现得非常糟糕。我没有将它与我替换子查询中的值的查询进行比较,因为我只是在单个查询中无法完成时才这样做(例如,我需要匹配不同服务器上的数据)。 / p>

顺便说一句,如果您还要对要加入的表中的值进行过滤,则使用LEFT JOIN毫无意义。

在所有情况下,请确保您在连接或IN子句中使用的键上有索引。