使用唯一索引删除重复项

Removing duplicates with unique index

我在两个 tables 字段 A、B、C、D 之间插入,相信我已经在 A、B、C、D 上创建了一个唯一索引以防止重复。然而,我不知何故只是简单地对这些做了一个正常的索引。因此插入了重复项。 2000万记录table.

如果我将现有索引从普通索引更改为唯一索引,或者只是为 A、B、C、D 添加新的唯一索引,是否会删除重复项或添加失败,因为存在唯一记录?我会测试它,但它有 3000 万条记录,我不想弄乱 table 或复制它。

如果你认为会有重复,添加唯一索引会失败。 首先检查有哪些重复项:

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

这可能是对 2000 万行的昂贵查询,但会为您提供所有重复键,从而阻止您添加主索引。 如果您在子查询中执行 where ,则可以将其拆分为更小的块:where a='some_value'

对于检索到的记录,您必须进行一些更改以使行唯一。如果完成(查询 returns 0 行),您应该可以安全地添加主索引。

回答您的问题 - 在具有重复值的列上添加 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'
*/

如果您的 table 中有重复项并且您使用

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 is a MySQL extension to standard SQL. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only one row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.

    As of MySQL 5.7.4, the IGNORE clause for ALTER TABLE is removed and its use produces an error.

(ALTER TABLE Syntax)

如果您的版本是 5.7.4 或更高版本 - 您可以:

  • 将数据复制到临时文件中 table(技术上不需要临时文件)。
  • 截断原来的table。
  • 创建唯一索引。
  • 然后用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;

If you use the IGNORE modifier, errors that occur while executing the INSERT statement are ignored. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row is discarded and no error occurs. Ignored errors generate warnings instead.

(INSERT Syntax)

另见:INSERT ... SELECT Syntax and Comparison of the IGNORE Keyword and Strict SQL Mode

您可以使用 ON DUPLICATE KEY UPDATE 而不是 IGNORE,这将使您能够控制哪些值应该优先。