MySQL Ошибка 1062 (23000): Duplicate entry 'value' for key 'PRIMARY'
Механизм контроля уникальности индексов в MySQL
Реляционная СУБД гарантирует целостность данных с помощью ограничений уникальности PRIMARY KEY и UNIQUE INDEX. Системная ошибка MySQL Error 1062 (SQLSTATE 23000): «Duplicate entry 'value' for key 'table.PRIMARY'» (или для любого именованного уникального индекса) возникает при попытке выполнения операторов INSERT или UPDATE, если вставляемое значение ключа уже присутствует в целевой таблице. Распространенные сценарии сбоя:
- Сбой счетчика AUTO_INCREMENT: Счетчик автоинкремента рассинхронизировался с фактическим максимальным значением первичного ключа в таблице (например, после ручной вставки с явным указанием ID или аварийного перезапуска сервера).
- Конфликты репликации данных (Master-Master / Master-Slave): Одновременная запись в один и тот же диапазон ID на двух разных узлах кластера.
- Повторная отправка формы / запроса клиентом (Double Submit): Отсутствие идемпотентности в API-эндпоинтах.
Бизнес-риски
Аварийная остановка потока репликации (Slave SQL Thread Stopped), сбой импорта выгрузок из 1С/ERP, потеря части пользовательских транзакций.
Варианты поведения при вставке дубликатов
| Конструкция SQL | Поведение при возникновении дубликата | Результат |
|---|---|---|
INSERT INTO ... | Прерывает запрос с Ошибкой 1062 и откатом стейтмента. | Ошибка выполнения. |
INSERT IGNORE INTO ... | Игнорирует ошибку, пропускает вставку дублирующей строки (Warning). | Запрос успешен (0 rows inserted). |
INSERT ... ON DUPLICATE KEY UPDATE | При совпадении ключа выполняет обновление указанных колонок. | Строка обновлена. |
REPLACE INTO ... | Физически удаляет старую строку (DELETE) и вставляет новую (INSERT). | Строка перезаписана (меняется auto_increment). |
Регламент локализации и исправления ошибок дублирования ключей
Сценарий 1: Синхронизация счетчика AUTO_INCREMENT с максимальным ID таблицы
Если ошибка возникает при вставке новой записи со значением первичного ключа по умолчанию (NULL):
-- 1. Определение текущего максимального значения ID в таблице:
SELECT MAX(id) FROM `my_table`;
-- Допустим, максимальный ID равен 15420
-- 2. Проверка текущего значения счетчика автоинкремента:
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
-- 3. Корректировка счетчика (устанавливаем значение MAX(id) + 1):
ALTER TABLE `my_table` AUTO_INCREMENT = 15421;Сценарий 2: Разрешение ошибки 1062 на реплике (MySQL Replication Slave)
Если репликация остановилась из-за дубликата ключа на Slave-сервере:
-- 1. Проверка статуса репликации:
SHOW SLAVE STATUS\G
-- Обратите внимание на Last_SQL_Errno: 1062
-- 2. Вариант А: Использование утилиты Percona Toolkit (Безопасная синхронизация данных):
-- pt-table-sync --execute --sync-to-master h=slave_host,D=my_database,t=my_table
-- 3. Вариант Б: Ручной пропуск одной ошибочной транзакции (GTID режим):
-- Получите номер транзакции из Last_Error (например: xxx:105)
STOP SLAVE;
SET GTID_NEXT = '3E11FA47-71CA-11E1-9E33-C80AA9429562:105';
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;
-- 4. Вариант В: Пропуск одной транзакции в классической репликации (Non-GTID):
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;Сценарий 3: Настройка смещения автоинкремента в Master-Master репликации
Чтобы два мастера никогда не генерировали одинаковые ID:
# На Сервере 1 (my.cnf):
auto_increment_increment = 2
auto_increment_offset = 1
# На Сервере 2 (my.cnf):
auto_increment_increment = 2
auto_increment_offset = 2Типовые ошибки администраторов
- Постоянное использование sql_slave_skip_counter: Пропуск транзакций «вслепую» приводит к накоплению критической рассинхронизации данных между мастером и репликой.
- Использование REPLACE INTO на таблицах с каскадными внешними ключами:
REPLACEделает неявныйDELETE, что может привести к каскадному удалению связанных строк в дочерних таблицах (ON DELETE CASCADE).
Инженеры ITSTM безопасно синхронизируют реплики с помощью Percona Toolkit и предотвратят возникновение конфликтов ключей.
Частые вопросы (FAQ)
Почему AUTO_INCREMENT может перескочить назад после перезапуска MySQL?
В MySQL 5.7 счетчики автоинкремента хранились только в оперативной памяти и инициализировались при старте через SELECT MAX(id). Начиная с MySQL 8.0 счетчик персистентно пишется в системный Redo Log.
Что делать, если достигнут предел типа данных (например, 127 для TINYINT или 2147483647 для INT)?
Счетчик упирается в максимальное значение типа данных, вызывая постоянную Ошибку 1062. Расширьте тип колонки: ALTER TABLE `table` MODIFY `id` BIGINT UNSIGNED AUTO_INCREMENT;
Влияет ли collation на дубликаты строк (например, 'admin' и 'Admin')?
Да. При использовании регистронезависимых коллаций (_ci, например utf8mb4_general_ci) строки 'admin' и 'Admin' считаются абсолютно идентичными и вызовут Ошибку 1062.
Как найти все дублирующиеся записи перед созданием UNIQUE индекса?
Выполните: SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;