Attention à TRUNCATE avec une table Inno DB

vendredi 7 octobre 2005 :: perrick :: MySQL :: 10 commentaires :: aucun trackback

Le truc avec les tests c'est qu'ils sont automatiques et précis. Très précis même. Donc quand ils renvoient un ID avec comme valeur "2" et que moi je m'attendait à une valeur "1", c'est qu'il y a un problème quelque part : une chose est sûr l'insertion de ma valeur dans la table de test ne marche pas comme il faut. Quand bien même tout à l'air de fonctionner dans l'application (un plugin pour openTIME). Après plusieurs tentatives infructueuses pour trouver l'origine du problème, je m'étais résolu -- bien malgré moi -- à accepter cette "fausse valeur".

Aujourd'hui ça recommence pour une nouvelle table : à une différence prêt, nous sommes vendredi soir et la pression de la semaine est tombée quelque peu. En creusant un peu, le problème vient d'un TRUNCATE table qui ne fonctionne pas à tous les coups. Au passage je me rends compte que mes nouvelles tables n'ont pas de type : MySQL par défaut se charge de les créer en Inno DB, alors que dans le reste d'openTIME j'utilise des tables MyISAM. J'ai eu du mal à commencer une recherche dans le manuel de MySQL : je n'ai encore jamais eu à faire à un bug dans des versions "stable". C'est donc choses faite : MySQL Bugs: #11946: truncate does not clear the auto_increment in innodb tables. Et il ne me reste qu'à attendre (et installer) MySQL 5 pour que le bug soit corrigé définitivement.

Vos commentaires et/ou trackbacks

Le vendredi 7 octobre 2005 à 20:06, commentaire par Eric Daspet :: #

En même temps l'auto-increment est fait pour être une valeur opaque. Si le fait d'obtenir 2 ou 659 à la place de 1 te pose problème c'est une erreur de ton coté (peut être un test trop rapidement rédigé).

La seule contrainte de l'auto-increment c'est de te donner une valeur unique. Il l'a fait.

Effectivement le fait de ne pas remettre à zéro l'auto-increment est un bug coté mysql, mais le fait que ça ait une influence autre que "j'en ai moins de disponnibles" est un bug de ton coté.

Le samedi 8 octobre 2005 à 09:56, commentaire par Sledge :: site :: #

Dommage ! InnoDB est quand même le format qui permet à MySQL de s'aligner au niveau des fonctionnalités sur les autres SGDB du marché (foreign keys, sub-requests, etc.)

Le samedi 8 octobre 2005 à 15:22, commentaire par perrick :: site :: #

Eric > je ne comprends pas à quoi tu fais allusion dans le "j'en ai moins de disponibles" : peut-être pourras-tu éclairer ma lanterne.

Sinon pour en revenir à la valeur renvoyée : le problème est bien celui de savoir "comment" il choisit cette valeur. Et donc pouvoir anticiper et écrire le test qui correspond. La meilleur preuve, c'est que l'application fonctionne quel que soit le moteur de base de données (MyISAM ou InnoDB).

Le dimanche 9 octobre 2005 à 18:57, commentaire par Eric :: #

> "j'en ai moins de disponibles"

Disons que si tu as une table qui est allé jusqu'à 1M d'identifiants, que tu tronque cette table sans remettre à zéro l'auto-incrément, le maximum sera plus vite atteint : tu as moins d'identifiants disponibles (les 1M premiers sont considérés comme "pris")

> le problème est bien celui de
> savoir "comment" il choisit cette
> valeur

Pourquoi ? ce qui t'importe c'est de savoir qu'il t'en a créé un et qu'il est unique, pas lequel il t'a envoyé. Ce que tu dois testé c'est sa présence et son unicité, pas sa valeur.

Le lundi 10 octobre 2005 à 11:25, commentaire par perrick :: site :: #

> Ce que tu dois testé c'est sa
> présence et son unicité, pas sa
> valeur.

Moi ça ne me suffit pas : je dois aussi vérifier que je peux le modifier et le supprimer. Et pour cela je vérifie que cet enregistrement précis à bien été impacté, pas celui d'avant, ni celui d'après. Pour que cette vérification soit effective j'ai besoin de connaitre la valeur qui a été déterminé par la base...

Dans les stratégies de test proposés par Marcus Baker (www.phpkitchen.com/index.... je m'appuie principalement sur la 2ème approche : celle-ci explique peut-être pourquoi j'ai besoin de connaître la valeur de l'ID.

Le lundi 10 octobre 2005 à 16:40, commentaire par Armel :: #

Oops, de passage, je me permets de réagir ici. Je partage l'avis d'Eric. Je pense que ce que tu dois tester, c'est l'obtention d'un identifiant unique. Point. Et ca tombe plutôt pas mal parceque c'est précisement ce que le SGBD est supposé te garantir. Il n'ira pas au delà. Il n'est pas fait pour cela.

Maintenant, Perrick, si le comportement du SGBD ne te convient pas ici (en particulier pour mener à bien ton scénario de test), je pense qu'une solution serait...de prendre en charge la gestion de tes auto-incréments par toi même. Et par là même, le comportement que tu en attends.

Rien de critique ici, je le précise :) Mais je pense que tu attends du SGBD un comportement qui n'est pas celui qu'il serait supposé te donner.

Mais j'ai peut-être raté un épisode :)

Armel.

Le lundi 10 octobre 2005 à 19:19, commentaire par perrick :: site :: #

Armel > Il y a bien une autre technique : plutôt que de prendre en charge la gestion des auto-increments, il suffit de choisir un moteur qui le fait de façon suffisamment transparente pour que je puisse le comprendre ;-)

Le lundi 10 octobre 2005 à 20:26, commentaire par pascaltje :: #

une question en passant: pourquoi utiliser TRUNCATE plutôt que DELETE?

dans la doc de mysql et notamment dans les commentaires, il y une piste intéressante:
dev.mysql.com/doc/mysql/f...

en gros:
- soit en redémarre le serveur pour repartir à zero dans l'id auto_increment
- soit on le met explicitement à zero:
ALTER TABLE test AUTO_INCREMENT=0;

j'adore manipuler les id! :)

Le mardi 11 octobre 2005 à 10:55, commentaire par Greg :: #

Je vais aussi peut être dire une hénaurme conneuhrie, mais en détruisant la table et en la recréant, tu aurais la garantie d'avoir un AUTO_INCREMENT tout frais non ?

Le mardi 11 octobre 2005 à 11:53, commentaire par perrick :: site :: #

La différence entre un TRUNCATE et un DELETE sur une table de type MyISAM, c'est la remise à O de l'AUTO_INCREMENT. Avec InnoDB, cette différence n'existe pas actuellement : elle arrive avec MySQL 5.0. Je profitais donc de cette différence pour faire d'une pierre deux coups.

Effectivement détruire la table et la recréer fonctionne aussi : c'est ce que je fais à chaque lancement d'une série de scénarios de tests. Et entre chaque scénario, je préfère effectuer un TRUNCATE. Dans ma tête, je me dis que c'est moins gourmand que de recréer la table. Même si je n'ai aucun benchmark pour me faire une opinion précise.

Ajouter un commentaire

Les commentaires pour ce billet sont fermés.