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
。
更多提示
- 如果你想更快地查询,不要做
SELECT *
只select你真正需要的字段。 - 确保你在related_field上有一个索引来加速等连接。
- 确保
group by
主键group by
。 - 如果你使用的是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
的表。 我需要的是
-
在
tabel_buku_besar
中tabel_buku_besar
具有account_code='101.100'
logging,其中companyarea='20000'
且IDR
为currency
-
我需要从
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 )