Nous avons une table MySQL qui a un champ auto-incrémenté défini comme INT (11). Ce tableau stocke à peu près une liste des travaux en cours d'exécution dans une application. À tout moment pendant la durée de vie de l'application, le tableau peut contenir des milliers d'entrées ou être complètement vide (c'est-à-dire que tout est terminé).
Le champ n'est associé à aucune clé étrangère.
L'incrémentation automatique semble se remettre à zéro de façon aléatoire, bien que nous n'ayons jamais pu piéger la réinitialisation.
Le problème devient évident parce que nous voyons le champ d'incrémentation automatique atteindre, disons, 600 000 enregistrements environ, puis un peu plus tard, le champ d'incrémentation automatique semble fonctionner dans les 1000 bas.
C'est presque comme si l'incrémentation automatique se réinitialise si la table est vide.
Est-ce possible et si c'est le cas, comment puis-je le désactiver ou changer la manière dont il se réinitialise?
Si ce n'est pas le cas, quelqu'un a-t-il une explication de la raison pour laquelle il pourrait faire cela?
Merci!
la source
Réponses:
http://dev.mysql.com/doc/refman/4.1/en/innodb-auto-increment-handling.html
Pour cette raison, lorsque le service (ou le serveur) redémarre, les événements suivants se produisent:
Donc, en clair, après le démarrage du service MySQL, il n'a aucune idée de la valeur d'incrémentation automatique de votre table. Ainsi, lorsque vous insérez une ligne pour la première fois, elle trouve la valeur maximale du champ qui utilise l'incrémentation automatique, ajoute 1 à cette valeur et utilise la valeur résultante. S'il n'y a pas de lignes, il commencera à 1.
C'était un problème pour nous, car nous utilisions la table et la fonction d'incrémentation automatique de mysql pour gérer proprement les identifiants dans un environnement multithread où les utilisateurs étaient redirigés vers un site de paiement tiers. Nous avons donc dû nous assurer que l'ID que le tiers avait obtenu et renvoyé était unique et resterait ainsi (et bien sûr, il est possible que l'utilisateur annule la transaction après avoir été redirigé).
Nous avons donc créé une ligne, obtenu la valeur d'auto-incrémentation générée, supprimé la ligne pour garder la table propre et transmis la valeur au site de paiement. Ce que nous avons fini par faire pour résoudre le problème de la façon dont InnoDB gère les valeurs AI était le suivant:
Cela conserve toujours le dernier transactionId généré sous forme de ligne dans la table, sans faire exploser inutilement la table.
J'espère que cela aide toute autre personne qui pourrait rencontrer cela.
Modifier (18/04/2018) :
Comme Finesse l'a mentionné ci-dessous, il semble que son comportement ait été modifié dans MySQL 8.0+.
https://dev.mysql.com/worklog/task/?id=6204
Le libellé de ce journal de travail est au mieux défectueux, mais il semble qu'InnoDB dans ces versions plus récentes prend désormais en charge les valeurs autoinc persistantes à travers les redémarrages.
-Gremio
la source
Nous avons rencontré ce problème et avons découvert que lorsque la table d'optimisation était exécutée sur une table vide, la valeur d'incrémentation automatique était également réinitialisée. Voir ce rapport de bogue MySQL .
Pour contourner ce problème, vous pouvez:
Au lieu de
OPTIMIZE TABLE
.Il semble que c'est ce que fait MySQL en interne (sans définir la valeur d'incrémentation automatique, évidemment)
la source
Juste un coup dans le noir - si l'application utilise un
TRUNCATE TABLE
pour vider la table une fois le traitement terminé, cela réinitialisera le champ d'incrémentation automatique. Voici une brève discussion sur la question. Bien que ce lien mentionne qu'InnoDB ne réinitialise pas les auto_increments sur un tronc, cela a été signalé comme un bug et corrigé il y a quelques années.En supposant que ma supposition est juste, vous pouvez passer de la troncature à la suppression pour résoudre le problème.
la source
Seule une réinitialisation explicite de cette valeur, ou une suppression / recréation de ce champ, ou toute autre opération violente similaire devrait jamais réinitialiser un compteur auto_increment. (Le TRUNCATE était une très bonne théorie.) Il semble impossible que vous emballiez soudainement un INT 32 bits lorsque la dernière valeur dont vous êtes témoin n'est que de 600k. Il ne devrait certainement pas être réinitialisé simplement parce que la table se vide. Vous avez soit un bug mysql ou quelque chose dans votre code PHP. Ou le gars dans la cabine d'à côté vous joue un tour.
Vous pouvez déboguer en activant le journal binaire , car il contiendra des instructions comme celle-ci tout au long:
Ensuite, au moins, vous pouvez voir tous les détails de ce qui arrive à cette table, y compris juste avant la réinitialisation du compteur.
la source
ALTER TABLE nom_table ENGINE = MyISAM
Fonctionne pour moi. Notre table est toujours très petite, donc pas besoin d'InnoDB.
la source
InnoDB ne stocke pas de valeur d'incrémentation automatique sur le disque, l'oublie donc lorsque le serveur MySQL est arrêté. Lorsque MySQL est démarré à nouveau, le moteur InnoDB restaure la valeur d'incrément automatique de cette façon:
SELECT (MAX(id) + 1) AS auto_increment FROM table
. Ceci est un bug qui est fixé dans la version MySQL 8.0.Modifiez le moteur de table pour résoudre le problème:
Ou mettez à jour le serveur MySQL vers la version 8.0 lors de sa sortie.
la source