Ошибка повторяющейся записи в MySQL при отсутствии повторяющейся записи (массовая загрузка через php) - PullRequest
6 голосов
/ 21 октября 2008

Я использую mysql (5.0.32-Debian_7etch6-log) , и у меня работает ночная массовая загрузка php (5.2.6) script (используя Zend_DB (1.5.1) через PDO), который выполняет следующие действия:

  1. усечение набора из 4 таблиц 'import'
  2. массовая вставка данных в эти 4 таблицы «импорта» (повторное использование идентификаторов, которые также были в таблицах ранее, но я обрезал всю таблицу, так что это не должно быть проблемой, верно?)
  3. если все идет хорошо, переименуйте «живые» таблицы в «temp», таблицы «import» - в «live», а затем таблицы «temp» (старые «live») в «import»

Это отлично работало в течение нескольких недель. Теперь я иногда получаю это где-то в середине процесса массовой загрузки:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '911' for key 1

Имейте в виду, что это не первый идентификатор, который был в таблице до усечения уже. Когда я просто снова запускаю скрипт вручную, он работает как шарм.

Есть идеи? оставшиеся индексы, может быть, какое-то отношение к переименованию?

Кроме того, когда я проверяю таблицу на предмет записи с идентификатором 911, ее там даже нет.

Ответы [ 6 ]

2 голосов
/ 22 октября 2008

Подобные ошибки могут возникать, когда таблица MyISAM становится поврежденной. Выполнение команды исправления для рассматриваемой таблицы - обычно все, что требуется для ее исправления:

> repair table mytablename;

Лучшее решение - не использовать MyISAM для таблиц, где данные постоянно меняются - InnoDB намного более пуленепробиваемый, и, как правильно указывает Пол, вы можете использовать транзакции для таблиц InnoDB, но не для MyISAM.

Кстати, я бы не стал переименовывать таблицы на лету - это довольно неуклюжая вещь, которую нужно делать регулярно, и может привести к некоторым очень неожиданным результатам, если у вас когда-нибудь будут другие пользователи в системе, пока происходит переименование на. Почему бы просто не сделать что-то вроде этого:

> truncate table temptable;
> truncate table importtable;

> #bulk insert new data
> insert into importtable(col1,col2,col3) 
> values(1,2,3),(4,5,6),(7,8,9);

> #now archive the live data
> insert into temptable(col1,col2,col3)
> select col1,col2,col3 from livetable;

> #finally copy the new data to live
> truncate table livetable;
> insert into livetable(col1,col2,col3)
> select col1,col2,col3 from importtable;

Конечно, если вы вставляете очень большое количество строк, то существует риск, что все ваши текущие данные будут недоступны до тех пор, пока вставка завершается, но в целом этот подход гораздо менее разрушителен для индексов, триггеров или что-нибудь еще, что может быть связано с соответствующими таблицами.

1 голос
/ 21 октября 2008

Очевидно, что были некоторые проблемы с блокировками или что-то в этом роде, я смог воспроизвести поведение, стреляя в операторы SELECT для затронутых и связанных таблиц в параллельном соединении.

теперь я использовал DELETE FROM вместо TRUNCATE и изменил операторы RENAME TABLE (где я сделал 3 переименования одновременно) на набор отдельных ALTER TABLE xxx RENAME TO zzz операторов и больше не могу воспроизвести ошибку.

так что это может быть решено. может быть, кто-то еще может получить прибыль от моего дня, проведенного с исследованиями и большим количеством проб и ошибок.

0 голосов
/ 16 октября 2009

Вы создаете новую запись с пропущенным полем 'id' (или NULL), НО ранее вы обновили другую запись и изменили ее «id» на «911». Другими словами, вы не можете создать другую запись, если взято значение AUTO_INCREMENT вашей таблицы.

0 голосов
/ 22 октября 2008

Вы используете транзакции? Вы можете устранить множество подобных проблем с транзакциями, особенно если можно заблокировать таблицы или установить режим изоляции транзакций на сериализуемый. Я не очень знаком с теми, кто работает с MySQL, но я считаю, что транзакции работают только с таблицами InnoDB (или это может быть устаревшим знанием).

0 голосов
/ 21 октября 2008

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

Можете ли вы воспроизвести его в своей тестовой среде? Не включайте журнал запросов в производстве.

Возможно, что таблица была повреждена, если проблема подлинная; это может быть вызвано несколькими причинами, но возможны хитрые аппаратные средства или сбой питания.

Проверьте журнал mysql, чтобы узнать, были ли у него какие-либо проблемы (или произошел сбой) в последнее время или в течение периода.

Опять же, все, что я могу предложить, это попытаться воспроизвести его в вашей тестовой среде. Создайте очень большие загрузки тестовых данных и многократно загружайте их.

0 голосов
/ 21 октября 2008

Может ли какой-либо другой скрипт вставляться в базу данных во время работы скрипта импорта?

...