Удаление дубликатов с уникальным индексом

я вставил между двумя полями таблиц A,B,C, D,полагая,что я создал уникальный индекс на A,B, C, D, чтобы предотвратить дубликаты. Однако я как-то просто сделал нормальный индекс на тех. Таким образом, дубликаты были вставлены. Это 20 миллионов записей в таблице.

Если я изменю существующий индекс с обычного на уникальный или просто добавлю новый уникальный индекс для A,B,C, D, будут ли удалены дубликаты или добавление завершится ошибкой, поскольку существуют уникальные записи? Я бы проверил его, но это 30 Mil records, и я не хочу испортите стол или дублируйте его.

4 ответов


если у вас есть дубликаты в таблице, и вы используете

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

запрос завершится с ошибкой 1062 (дубликат ключа).

но если вы используете IGNORE

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

дубликаты будут удалены. Но в документации не указано, какая строка будет сохранена:

  • IGNORE является расширением MySQL для стандартного SQL. Он контролирует, как ALTER TABLE работает, если в новой таблице есть дубликаты на уникальных ключах или если предупреждения возникают, когда включен строгий режим. Если IGNORE - это не указан, то копирование прерывается и откатывается, если дубликат ключа ошибки происходить. Если IGNORE указано, только одна строка используется строк с дубликаты на уникальном ключе. Другие конфликтующие строки удаляются. Неправильные значения усекаются до максимально допустимого соответствия значение.

    Начиная с MySQL 5.7.4, предложение 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, подряд дублирует существующий или PRIMARY KEY значение в таблице вызывает ошибку повторяющегося ключа и оператор прерывается. С IGNORE строка удаляется и ошибка не возникает. Игнорировать ошибки вместо этого генерируйте предупреждения.

(вставить синтаксис)

Смотрите также: вставить ... Выберите синтаксис и сравнение ключевого слова IGNORE и строгого режима SQL


Если вы думаете, что будут дубликаты, добавление уникального индекса завершится неудачей. сначала проверьте, какие дубликаты есть:

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 строк) вы должны быть в безопасности, чтобы добавить основной индекс.


вместо IGNORE вы можете использовать при обновлении дубликатов ключей, что даст вам контроль над тем, какие значения должны преобладать.


чтобы ответить на ваш вопрос-добавление 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'
*/