検査したいデータベースにいくつかの重複があるので、どの重複を確認するために何をしたか、これを行いました:
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
このようにして、relevant_fieldが複数回発生するすべての行を取得します。このクエリの実行には数ミリ秒かかります。
今、私は重複のそれぞれを検査したかったので、上記のクエリのrelevant_fieldでsome_tableの各行を選択できると思ったので、私はこれをしました:
SELECT *
FROM some_table
WHERE relevant_field IN
(
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)
からビュー "temp_view"を作成し、次に代わりに2番目のクエリを作成しようとしました。
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT relevant_field
FROM temp_view
)
そしてそれはうまく機能します。 MySQLはこれを数ミリ秒で行います。
ここで何が起こっているのか説明できるSQLの専門家はいますか?
サブクエリは相関クエリであるため、各行に対して実行されています。次のように、サブクエリからすべてを選択することにより、相関クエリを非相関クエリにすることができます。
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.*, 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に含まれている必要があると思う、そうでなければhaving
句はエラーを与えるだろうが、私は100%確信がない
サブクエリでIN
を使用しないでください。これは非常に遅いことで有名です。
値の固定リストでIN
のみを使用してください。
その他のヒント
SELECT *
を実行しないでください。本当に必要なフィールドのみを選択してください。relevant_field
にインデックスがあることを確認してください。group by
を確認してください。IN (select
クエリの90%の一般的なソリューション
このコードを使用
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 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;
私のデータベースの1つでクエリを試し、サブクエリへの結合として書き直しました。
これははるかに速く動作しました、試してみてください!
これを試して
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;
遅いsqlクエリをwww.prettysql.netで再フォーマットしました
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
);
それは役立ちますか?
まず、重複する行を見つけて、行の数を見つけることができる回数を使用し、このように番号順に並べます。
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
)
その後、テーブルを作成し、結果を挿入します。
create table CopyTable
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
)
最後に、重複行を削除します。Noはstart 0です。各グループの最初の番号を除き、重複行をすべて削除します。
delete from CopyTable where No!= 0;
データが大きくなると、クエリの最適化のためにmysql WHERE INがかなり遅くなることがあります。 STRAIGHT_JOINを使用して、mysqlにクエリをそのまま実行するように指示してみてください。
SELECT STRAIGHT_JOIN table.field FROM table WHERE table.id IN (...)
しかし注意してください:ほとんどの場合、mysqlオプティマイザーはかなりうまく機能するので、この種の問題がある場合にのみ使用することをお勧めします
これは、tabel_buku_besar
という名前のテーブルがある場合に似ています。必要なのは
account_code='101.100'
にtabel_buku_besar
があり、companyarea='20000'
があり、さらにIDR
がcurrency
であるレコードを探しています
ステップ1と同じaccount_codeを持つが、ステップ1の結果にtabel_buku_besar
がある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`
これは、値が存在するかどうかを見つけるのに最も効率的であることがわかります。値が存在しないかどうかを見つけるためにロジックを簡単に反転できます(つまり、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
* relevant_fieldを、テーブルに存在するチェックする値の名前に置き換えます
* primaryKeyを比較テーブルの主キー列の名前に置き換えます。