158

データベースに検査したい重複がいくつかあるので、どれが重複しているかを確認するために行ったことは、次のとおりです。

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

このようにして、relevant_field が複数回発生するすべての行を取得します。このクエリの実行には数ミリ秒かかります。

ここで、各重複を検査したかったので、上記のクエリで related_field を使用して some_table の各行を SELECT できると考えたので、次のようにしました。

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

これは、何らかの理由で非常に遅いことが判明しました (数分かかります)。それを遅くするためにここで何が起こっているのでしょうか?related_field は索引付けされています。

最終的に、最初のクエリからビュー「temp_view」を作成してから(SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1)、2番目のクエリを次のように作成してみました。

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

そして、それはうまく機能します。MySQL はこれを数ミリ秒で実行します。

何が起こっているのか説明できる SQL 専門家はいますか?

4

11 に答える 11

136

サブクエリは相関クエリであるため、行ごとに実行されています。次のように、サブクエリからすべてを選択することで、相関クエリを非相関クエリにすることができます。

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
)
于 2011-05-27T21:18:27.183 に答える
6

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
 );

それは役に立ちますか?

于 2011-05-26T08:06:15.320 に答える
6

サブクエリと結合

http://www.scribd.com/doc/2546837/New-Subquery-Optimizations-In-MySQL-6

于 2011-05-26T08:46:16.720 に答える
3

これを試して

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;
于 2013-04-04T10:16:05.897 に答える
3

まず、重複する行を見つけて、行の数が何回使用されているかを見つけ、次のように番号で並べ替えることができます。

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 は開始 0 です。各グループの最初の番号を除いて、すべての重複行を削除します。

delete from  CopyTable where No!= 0;

于 2017-08-21T12:53:13.327 に答える
0

これは、という名前のテーブルがある私の場合と似ていますtabel_buku_besar。私が必要なのは

  1. account_code='101.100'have in tabel_buku_besarwhich havecompanyarea='20000'および have IDRasのレコードを探していますcurrency

  2. tabel_buku_besarステップ1と同じaccount_codeを持つすべてのレコードを取得する必要がありますがtransaction_number、ステップ1の結果 があります

を使用している間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`
于 2014-09-25T03:43:54.170 に答える
0

relevant_fieldサブクエリは、IN句のサブクエリとの比較ごとに 1 回実行されるため、低速です。次のように回避できます。

SELECT *
FROM some_table T1 INNER JOIN 
(
    SELECT relevant_field
    FROM some_table
    GROUP BY relevant_field
    HAVING COUNT(*) > 1
) T2 
USING(relevant_field)

これにより、派生テーブルが (大きすぎて収まらない場合を除き、メモリ内に) T2 として作成され、次にINNER JOINT1 と一緒に作成されます。JOIN は 1 回発生するため、クエリは 1 回実行されます。

これは、ピボットを使用してバルク データ テーブルをより具体的なデータ テーブルに関連付け、より具体的なデータ テーブルの関連行のサブセットに基づいてバルク テーブルのカウントを生成するケースを最適化する場合に特に便利です。大量の行を 5% 未満に絞り込むことができれば、結果として得られる疎アクセスは通常、完全なテーブル スキャンよりも高速になります。

つまり、製品の数を参照する Users テーブル (条件)、Orders テーブル (ピボット)、および LineItems テーブル (バルク) があります。PostCode「90210」でユーザーごとにグループ化された製品の合計が必要です。この場合、JOIN は を使用する場合よりも桁違いに小さいWHERE relevant_field IN( SELECT * FROM (...) T2 )ため、特にその JOIN がディスクにスピルしている場合ははるかに高速になります!

于 2021-11-12T21:04:03.323 に答える