2008-10-21 10 views
6

J'utilise mysql (5.0.32-Debian_7etch6-log) et j'ai une charge en vrac tous les soirs de course php (5.2.6) écriture (en utilisant Zend_Db (1.5.1) via AOP) qui effectue les opérations suivantes:mysql en double erreur d'entrée quand il n'y a pas d'entrée en double (charge en vrac via php)

  1. tronquant un ensemble de tableaux 4 'importation'
  2. vrac insertion de données dans ces 4 tables 'd'importation' (réutiliser les identifiants qui ont déjà été dans les tables, mais j'ai tronqué la table entière, ce qui ne devrait pas être un problème, ?)
  3. Si tout se passe bien, renommez les tables 'live' en 'temp', les tables 'import' en 'live' puis les tables 'temp' (old 'live') 'import'

Cela a fonctionné très bien pendant des semaines. Maintenant, je reçois ce occassionally, quelque part au milieu de l'ensemble du processus de chargement en vrac:

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

Rappelez-vous que, ce n'est pas le premier identifiant qui a été dans la table avant la troncature déjà. Quand je recommence le script manuellement, ça fonctionne comme un charme.

Des idées? restes index, quelque chose à voir avec le changement de nom peut-être?

En outre, lorsque je vérifie la table pour une entrée avec l'ID 911 par la suite, il n'est même pas là.

Répondre

0

Est-ce qu'un autre script peut être inséré dans la base de données pendant l'exécution de votre script d'importation?

0

Avez-vous essayé d'activer le journal des requêtes pour voir si vous insérez réellement un doublon? Pouvez-vous le reproduire dans votre environnement de test? N'activez pas le journal de requête en production.

Il est possible que la table ait été endommagée si le problème est réel; Cela peut être causé par un certain nombre de choses, mais le matériel douteux ou la panne de courant sont des possibilités.

Vérifiez le journal mysql pour voir s'il a eu des problèmes (ou s'est écrasé) récemment ou pendant la période.

Encore une fois, tout ce que je peux suggérer est d'essayer de le reproduire dans votre environnement de test. Créez de très grandes quantités de données de test et chargez-les de manière répétée.

1

Apparemment, il y avait quelques problèmes de verrouillage ou quelque chose, j'ai été en mesure de reproduire le comportement en tirant des instructions 'SELECT' sur les tables affectées et connexes dans une connexion parallèle.

maintenant j'utilisé DELETE FROM au lieu de TRUNCATE et changé les RENAME TABLE déclarations (où je l'ai fait 3 renomme à la fois chacun) à un tas de déclarations ALTER TABLE xxx RENAME TO zzz unique et ne peut pas reproduire l'erreur plus.

donc cela pourrait être résolu. peut-être que quelqu'un d'autre peut profiter de ma journée passée avec la recherche et beaucoup d'essais et d'erreurs.

0

Utilisez-vous des transactions?Vous pouvez éliminer beaucoup de ces types de problèmes avec les transactions, en particulier s'il est possible de verrouiller les tables ou de définir le mode d'isolation des transactions sur sérialisable. Je ne suis pas vraiment familier avec ceux sur MySQL, mais je crois que les transactions ne fonctionnent que sur les tables InnoDB (ou qui pourraient être des connaissances obsolètes).

2

Des erreurs de ce type peuvent survenir lorsqu'une table MyISAM est corrompue. L'exécution de la commande de réparation sur la table en question est généralement tout ce qu'il faut pour y remédier:

> repair table mytablename; 

Une meilleure solution est de ne pas utiliser MyISAM pour les tables où les données sont en constante évolution - InnoDB est beaucoup plus l'épreuve des balles, et que Paul précise à juste titre que vous pouvez utiliser des transactions sur les tables InnoDB, mais pas sur MyISAM. D'ailleurs, j'éviterais de renommer les tables à la volée - c'est une chose assez maladroite à faire sur une base régulière, et pourrait causer des résultats très inattendus si vous avez d'autres utilisateurs sur le système alors que le changement de nom est passe. Pourquoi ne pas simplement faire quelque chose comme ceci:

> 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; 

Bien sûr, si vous insérez un très grand nombre de lignes, le risque serait que toutes vos données en direct est disponible aussi longtemps que l'insert faut pour terminer, mais globalement, cette approche est beaucoup moins destructrice pour les index, les déclencheurs ou toute autre chose qui pourrait être liée aux tables en question.

0

Vous créez un nouvel enregistrement avec le champ 'id' omis (ou NULL), MAIS précédemment vous avez mis à jour un autre enregistrement et l'avez changé 'id' en '911'. En d'autres termes, vous ne pouvez pas créer un autre enregistrement si la valeur AUTO_INCREMENT de votre table est prise.