web-dev-qa-db-ja.com

一意のインデックスを持つ重複を削除する

重複を防ぐために、A、B、C、Dに一意のインデックスを作成したと考えて、2つのテーブルフィールドA、B、C、Dの間に挿入しました。しかし、私はどういうわけかそれらに通常のインデックスを作成しました。そのため、重複が挿入されました。 2,000万件のレコードテーブルです。

既存のインデックスを通常から一意に変更した場合、または単にA、B、C、Dの新しい一意のインデックスを追加した場合、一意のレコードが存在するため重複は削除されますか、または追加に失敗しますか?私はそれをまだテストします、それは30 milレコードであり、テーブルを台無しにしたり複製したりすることは望みません。

17
user3649739

テーブルに重複があり、使用する場合

ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

クエリはエラー1062(重複キー)で失敗します。

ただし、IGNOREを使用する場合

-- (only works before MySQL 5.7.4)
ALTER IGNORE TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

重複は削除されます。ただし、ドキュメントでは、保持する行を指定していません。

  • IGNOREは、標準SQLのMySQL拡張機能です。新しいテーブルの一意のキーに重複がある場合、または厳格モードが有効になっているときに警告が発生する場合、ALTER TABLEの動作を制御します。 IGNOREが指定されていない場合、重複キーエラーが発生するとコピーは中止され、ロールバックされます。 IGNOREが指定されている場合、一意のキーに重複する行の1つの行のみが使用されます。他の競合する行は削除されます。誤った値は、最も近い一致する許容値に切り捨てられます。

    MySQL 5.7.4以降、ALTER TABLEのIGNORE句は削除され、その使用はエラーを生成します。

ALTER TABLE構文

バージョンが5.7.4以降の場合-次のことができます。

  • データを一時テーブルにコピーします(技術的に一時である必要はありません)。
  • 元のテーブルを切り捨てます。
  • 一意のインデックスを作成します。
  • そして、INSERT IGNORE(まだ利用可能です)でデータをコピーします。
CREATE TABLE tmp_data SELECT * FROM mytable;
TRUNCATE TABLE mytable;
ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
INSERT IGNORE INTO mytable SELECT * from tmp_data;
DROP TABLE tmp_data;

IGNORE修飾子を使用すると、INSERTステートメントの実行中に発生したエラーは無視されます。たとえば、IGNOREがない場合、テーブル内の既存のUNIQUEインデックスまたはPRIMARY KEY値を複製する行は重複キーエラーを引き起こし、ステートメントは中止されます。 IGNOREを使用すると、行は破棄され、エラーは発生しません。無視されたエラーは、代わりに警告を生成します。

(INSERT構文)

参照: INSERT ... SELECT構文 および IGNOREキーワードと厳格なSQLモードの比較

53
Paul Spiegel

重複があると思われる場合、一意のインデックスの追加は失敗します。最初に重複があるかどうかを確認します。

select * from
(select a,b,c,d,count(*) as n from table_name group by a,b,c,d) x
where x.n > 1

これは20M行の高価なクエリかもしれませんが、すべての重複キーを取得するため、プライマリインデックスを追加できません。サブクエリでwhereを実行すると、これを小さなチャンクに分割できます:where a='some_value'

取得したレコードについては、行を一意にするために何かを変更する必要があります。それが完了したら(クエリは0行を返します)、プライマリインデックスを追加しても安全です。

4
verhie

IGNOREの代わりにON DUPLICATE KEY UPDATEを使用すると、どの値を優先するかを制御できます。

2
Oriol Vilaseca

質問に答えるには、重複する値を持つ列にUNIQUE制約を追加するとエラーがスローされます。

たとえば、次のスクリプトを試すことができます。

CREATE TABLE `USER` (
  `USER_ID` INT NOT NULL,
  `USERNAME` VARCHAR(45) NOT NULL,
  `NAME` VARCHAR(45) NULL,
  PRIMARY KEY (`USER_ID`));

INSERT INTO USER VALUES(1,'Apple', 'woz'),(2,'Apple', 'jobs'),
(3,'google', 'sergey'),(4,'google', 'larry');

ALTER TABLE `USER` 
ADD UNIQUE INDEX `USERNAME_UNIQUE` (`USERNAME` ASC);
/*
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1062: Duplicate entry 'Apple' for key 'USERNAME_UNIQUE'
*/
0
Sarath Chandra