MySQL的 – selectWHERE字段IN(子查询) – 极其缓慢,为什么?

我在数据库中有一些重复的东西,我想检查一下,所以我做了什么来看看哪些是重复的,我这样做了:

SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1 

这样,我将得到不止一次发生的related_field的所有行。 这个查询需要几毫秒才能执行。

现在,我想检查每个重复项,所以我想我可以在some_table中select每行,并在上面的查询中使用relevant_field,所以我这样做:

 SELECT * FROM some_table WHERE relevant_field IN ( SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1 ) 

由于某种原因(这需要几分钟的时间),这样会变得exception缓慢。 到底究竟是怎么回事呢? relevant_field被编入索引。

最后,我试图从第一个查询(SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1) related_field (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1) related_field (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1)创build一个视图“temp_view”,然后使我的第二个查询是这样的:

 SELECT * FROM some_table WHERE relevant_field IN ( SELECT relevant_field FROM temp_view ) 

这工作得很好。 MySQL在几毫秒内完成这个工作。

这里的任何SQL专家谁可以解释发生了什么事?

重写查询到这个

 SELECT st1.*, st2.relevant_field FROM sometable st1 INNER JOIN sometable st2 ON (st1.relevant_field = st2.relevant_field) GROUP BY st1.id /* list a unique sometable field here*/ HAVING COUNT(*) > 1 

我认为st2.relevant_field必须在select,因为否则的条款会给出一个错误,但我不是100%肯定

切勿IN子查询中使用IN ; 这是非常缓慢的。
只有IN固定的值列表中使用IN

更多提示

  1. 如果你想更快地查询,不要做SELECT *只select你真正需要的字段。
  2. 确保你在related_field上有一个索引来加速等连接。
  3. 确保group by主键group by
  4. 如果你使用的是InnoDB, 而且你只select索引字段(而且事情不是很复杂) ,那么MySQL将只使用索引来parsing你的查询,从而加快速度。

一般解决scheme为90%的您的IN (select查询

使用这个代码

 SELECT * FROM sometable a WHERE EXISTS ( SELECT 1 FROM sometable b WHERE a.relevant_field = b.relevant_field GROUP BY b.relevant_field HAVING count(*) > 1) 

子查询正在为每一行运行,因为它是一个相关的查询。 通过select子查询中的所有内容,可以将相关查询转换为不相关的查询,如下所示:

 SELECT * FROM ( SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1 ) AS subquery 

最后的查询将如下所示:

 SELECT * FROM some_table WHERE relevant_field IN ( SELECT * FROM ( SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1 ) AS subquery ) 
 SELECT st1.* FROM some_table st1 inner join ( SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1 )st2 on st2.relevant_field = st1.relevant_field; 

我已经在我的一个数据库上试过了你的查询,并且还试图将它重写为一个子查询的连接。

这工作了很多,试试吧!

尝试这个

 SELECT t1.* FROM some_table t1, (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT (*) > 1) t2 WHERE t1.relevant_field = t2.relevant_field; 

我已经用www.prettysql.net重新格式化了你的慢sql查询

 SELECT * FROM some_table WHERE relevant_field in ( SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT ( * ) > 1 ); 

在查询和子查询中使用表时,应该始终同时使用两个表,如下所示:

 SELECT * FROM some_table as t1 WHERE t1.relevant_field in ( SELECT t2.relevant_field FROM some_table as t2 GROUP BY t2.relevant_field HAVING COUNT ( t2.relevant_field ) > 1 ); 

这有帮助吗?

有时当数据变大时,由于查询优化,MySQL WHERE IN可能会很慢。 尝试使用STRAIGHT_JOIN来告诉mysql执行查询,例如

 SELECT STRAIGHT_JOIN table.field FROM table WHERE table.id IN (...) 

但要小心:在大多数情况下,mysql优化器工作得很好,所以我build议只有在遇到这种问题时才使用它

这与我的情况类似,我有一个名为tabel_buku_besar的表。 我需要的是

  1. tabel_buku_besartabel_buku_besar具有account_code='101.100'logging,其中companyarea='20000'IDRcurrency

  2. 我需要从tabel_buku_besar获取所有logging,其中account_code与第1步相同,但在第1步中有transaction_number结果

同时使用select ... from...where....transaction_number in (select transaction_number from ....) ,我的查询运行速度非常慢,有时会导致请求超时或使我的应用程序不响应…

我尝试这个组合,结果…不错…

 `select DATE_FORMAT(L.TANGGAL_INPUT,'%d-%m-%y') AS TANGGAL, L.TRANSACTION_NUMBER AS VOUCHER, L.ACCOUNT_CODE, C.DESCRIPTION, L.DEBET, L.KREDIT from (select * from tabel_buku_besar A where A.COMPANYAREA='$COMPANYAREA' AND A.CURRENCY='$Currency' AND A.ACCOUNT_CODE!='$ACCOUNT' AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) L INNER JOIN (select * from tabel_buku_besar A where A.COMPANYAREA='$COMPANYAREA' AND A.CURRENCY='$Currency' AND A.ACCOUNT_CODE='$ACCOUNT' AND (A.TANGGAL_INPUT BETWEEN STR_TO_DATE('$StartDate','%d/%m/%Y') AND STR_TO_DATE('$EndDate','%d/%m/%Y'))) R ON R.TRANSACTION_NUMBER=L.TRANSACTION_NUMBER AND R.COMPANYAREA=L.COMPANYAREA LEFT OUTER JOIN master_account C ON C.ACCOUNT_CODE=L.ACCOUNT_CODE AND C.COMPANYAREA=L.COMPANYAREA ORDER BY L.TANGGAL_INPUT,L.TRANSACTION_NUMBER` 

我发现这是find一个值是否是最有效率的,逻辑可以很容易地被反转来find一个值是否不存在(即IS NULL)。

 SELECT * FROM primary_table st1 LEFT JOIN comparision_table st2 ON (st1.relevant_field = st2.relevant_field) WHERE st2.primaryKey IS NOT NULL 

*用您想要检查的值的名称replacerelevant_field存在于您的表中

*将primaryKeyreplace为比较表上主键列的名称。

首先,你可以find重复的行,find行的数量是多less次,并按照这个数字来sorting;

 SELECT q.id,q.name,q.password,q.NID,(select count(*) from UserInfo k where k.NID= q.NID) as Count, ( CASE q.NID WHEN @curCode THEN @curRow := @curRow + 1 ELSE @curRow := 1 AND @curCode := q.NID END ) AS No FROM UserInfo q, ( SELECT @curRow := 1, @curCode := '' ) rt WHERE q.NID IN ( SELECT NID FROM UserInfo GROUP BY NID HAVING COUNT(*) > 1 )