2013-05-06 62 views
3

我有两个级别的过滤我需要做一些相关的数据。第一个查询看起来像:MySQL IN子句使用子选择与值列表

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层查询结构之间?
  2. 有没有更好的方法来构造这2个查询?

基准

我没有完全测试,但跑我的版本,并通过Barmar发布的版本,对我的数据。我的查询在大约4.23秒内运行,而Barmar的版本只运行了0.60秒。这是一个85%的改善!

+0

记住性能最好,唯一的答案是:**基准**。您操作的数据类型,MySQL配置以及您所在硬件的属性,它们将对任何查询的性能产生巨大影响。 – tadman 2013-05-06 17:27:34

+0

绝对!但我对这些查询的理论知之甚少,无法知道哪些方法“已知”效率低下。由于我们的数据库没有经过微调,所以“标准理论”可能会涵盖我的案例。 – Elie 2013-05-06 17:31:12

+0

如果您关心速度,则需要进行基准测试。我试过的表面上看起来很荒谬的事情,只是十种不同方法中的一种,但它以某种方式大大超越了所有其他方法。 MySQL是一个不可预知的野兽。如果这两种方法都能产生正确的数据,下一步就是在可能的情况下根据实际生产数据进行测试,或者尽可能使用真实的传真。 – tadman 2013-05-06 17:41:28

回答

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)查询可怕的执行。我没有将它与查询替换为子查询中的值进行比较,因为我只在无法在单个查询中执行此操作(例如,我需要匹配不同服务器上的数据)时才这样做。

顺便说一句,如果您还要过滤正在连接的表中的值,则无需使用LEFT JOIN

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

+0

感谢您的额外方法。并且您对JOIN的评论很好。 – Elie 2013-05-06 17:44:57

+0

有时甚至可以在where子句中添加字段以增加效果。但是,如果您的t3.field2可能只有两个值'Y'或'N',将其添加到索引中将毫无意义。但有时在某些RDBMS /情况下,这可能会提高索引被使用的机会。 – Nabheet 2013-05-06 18:09:02

+2

对,你通常只需要列上的索引来显着减少行数。一个Y/N字段可能会将行数减半,这没有多大帮助。不过,将它作为组合索引的一部分可能很有用。 – Barmar 2013-05-06 18:11:19