[MySQL] Etude du fonctionnement d'InnoDB

Je suis en train de regarder comment fonctionne MySQL avec InnoDB.
Le systeme de transaction est classique, mais on m’avait rapporte un probleme rigolo:
Si on genere une table avec des contraintes et que les tables lies sont alphabetiquement apres la table liee, ca chie a la restoration. Exemple:

[code]CREATE TABLE alpha (
 aid int(11) NOT NULL auto_increment,
 product_category int(11) NOT NULL default ‹ 0 ›,
 product_id int(11) NOT NULL default ‹ 0 ›,
 customer_id int(11) NOT NULL default ‹ 0 ›,
 PRIMARY KEY  (aid),
 KEY product_category (product_category,product_id),
 KEY customer_id (customer_id),
 CONSTRAINT alpha_ibfk_1 FOREIGN KEY (product_category, product_id) REFER
ENCES product (category, id) ON UPDATE CASCADE,
 CONSTRAINT alpha_ibfk_2 FOREIGN KEY (customer_id) REFERENCES customer ( id)
) TYPE=InnoDB;

INSERT INTO alpha VALUES (1,1,1,2);
INSERT INTO alpha VALUES (2,1,2,1);

CREATE TABLE customer (
 id int(11) NOT NULL default ‹ 0 ›,
 PRIMARY KEY  (id)
) TYPE=InnoDB;

INSERT INTO customer VALUES (1);
INSERT INTO customer VALUES (2);

CREATE TABLE product (
 category int(11) NOT NULL default ‹ 0 ›,
 id int(11) NOT NULL default ‹ 0 ›,
 price decimal(10,0) default NULL,
 PRIMARY KEY  (category,id)
) TYPE=InnoDB;

INSERT INTO product VALUES (1,1,‹ 10 ›);
INSERT INTO product VALUES (1,2,‹ 20 ›);
INSERT INTO product VALUES (2,2,‹ 200 ›);[/code]
La, ca plante totalement a la restauration, vu que les tables a lier sont creees apres la table en relation (oui, c’est vraiment tres con).
La solution (ou plutot le workaround bien degueu), c’est de faire ca:

[code]SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS = 0;

—Code SQL a restaurer

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;[/code]
Oui, c’est uber barbare comme workaround.
De fait, ca passe comme une lettre a la poste. Probleme, si le dump est inconsistent a la base, ca passe aussi. Pour faire un essai, j’ai vire la ligne suivante:
INSERT INTO customer VALUES (2);

Ce INSERT est pourtant obligatoire pour la table alpha (premiere ligne)

J’ai donc maintenant une BDD qui a un probleme de FK, et j’essaye de trouver une commande qui verifie la consistence de ma BDD.
Je pensais avoir trouver la solution avec cette page qui explique comment tester les tables, mais ca donne rien:
ANALYSE TABLE dit OK, de meme que CHECK TABLE, malgre l’option EXTENDED active. J’ai fait le test sur toutes les tables, rien a faire, il voit pas l’erreur.

Rappel de l’etat des tables:

[code]mysql> select * from customer;
±—+
| id |
±—+
|  1 |
±—+
–Erreur ici: il devrait y avoir 2 aussi.

mysql> select * from alpha;
±----±-----------------±-----------±------------+
| aid | product_category | product_id | customer_id |
±----±-----------------±-----------±------------+
|      1 |                       1 |              1 |               2 | <–cette ligne doit poser probleme.
|      2 |                       1 |              2 |               1 |
±----±-----------------±-----------±------------+

mysql> select * from product;
±---------±—±------+
| category | id | price |
±---------±—±------+
|             1 |   1 |      10 |
|             1 |   2 |      20 |
|             2 |   2 |    200 |
±---------±—±------+[/code]
Quelqu’un connait une solution pour tester la consistence ? (google est pas mon ami, il me renvoie sur check table, qui marche pas, donc)

Note: using mysql-server 4.0.22-2 , Sarge daily updated version.

Merci d’avance :stuck_out_tongue:

LoneWolf
J’ai surement du rater une etape, mais laquelle? :stuck_out_tongue:

Je vais peut-être dire une connerie, et tu as déjà du y penser, mais pourquoi tu ne restaures pas dans l’ordre que tu désires (table de réf, puis table de fait), au pire en passant par une base intermediaire ?

J’ai trouvé quelque chose qui pourrait te servir dans les commentaires de la doc mysql : http://dev.mysql.com/doc/mysql/fr/InnoDB_f…onstraints.html

Quelqu’un propose un script pour vérifier l’intégrité des références :

[code]#!/bin/sh

find-fk-conflicts.sh

© 2004 Turadg Aleahmad, licensed under GPL

USAGE: find-fk-conflict.sh child_table child_key parent_table parent_key

NOTE: set this

db=“TARGET DATABASE”

child_table=$1
child_key=$2
parent_table=$3
parent_key=$4

query=“SELECT $child_table.$child_key FROM $child_table LEFT JOIN $parent_table
ON ( $child_table.$child_key = $parent_table.$parent_key)
WHERE $child_table.$child_key IS NOT NULL AND $parent_table.$parent_key IS NULL;

mysql --verbose -u root -e “$query” $db[/code]

A première vue, rien de trivial pour ton cas, mysql se poutre bien sur la restauration.

[quote name=‹ phili_b › date=’ 23 Dec 2004, 14:06’]Je vais peut-être dire une connerie, et tu as déjà du y penser, mais pourquoi tu ne restaures pas dans l’ordre que tu désires (table de réf, puis table de fait), au pire en passant par une base intermediaire ?
[right][post=« 315888 »]<{POST_SNAPBACK}>[/post][/right][/quote]
C’est une solution qui marcherait dans mon cas d’exemple, mais imagine une base qui fait 100Mo de data, c’est absolument injouable.

Styx: Ok pour ta solution, mais ca reste une requete SQL classique, pas un systeme de verification de consistence integre a la base.

LoneWolf
MySQL, des qu’on commence a l’utiliser vraiment, il perd de son aura :stuck_out_tongue:

Ahaha, pti joueur, chez nous au taff on a des tables de 4Go :stuck_out_tongue:

[quote name=‹ LoneWolf › date=’ 23 Dec 2004, 14:25’]C’est une solution qui marcherait dans mon cas d’exemple, mais imagine une base qui fait 100Mo de data, c’est absolument injouable.
[right][post=« 315897 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Pareil que [PERE]Cil, je vois pas en quoi 100 Mo poseraient problème si t’es pas limité dans le temps ni dans l’espace :stuck_out_tongue:
Le seul problème à mon avis serait, si tu ne la connait pas bien, de bien comprendre la structure de la base afin de tout remettre dans le bon ordre si jamais y’a un nombre de tables démentiel. Pis faut tout se taper à la main, mais bon, c’est juste du copier coller une fois qu’on connait l’ordre.

Ca pourrait être très intéréssant à automatiser comme truc, avec un programme qui parse le code du dump SQL de création des tables et insertion, comprenne la structure, et remette tout dans le bon ordre :stuck_out_tongue: (Par contre je ne connais pas de programme qui fasse ca…)

[quote name=‹ LoneWolf › date=’ 23 Dec 2004, 14:25’]Styx: Ok pour ta solution, mais ca reste une requete SQL classique, pas un systeme de verification de consistence integre a la base.
[right][post=« 315897 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Bah rien ne t’empèche d’aller fouiller dans les métadonnées pour récupérer toutes les contraintes de FK, et de lancer cette requête pour chacune avec un petit script pour te faire tout ca automatiquement.
Comment on fait exactement? Hum… euh… aucune idée, mais ca doit à priori être faisable ^^.
Comment ? Tu veux vérifier la consistence de toutes les tables, et sur toutes les contraintes déclarées, et pas que sur les FK ? Euh… bah le script risque d’être légèrement plus long du coup :stuck_out_tongue:

[Edit] : Petite update

Voilà ce que j’ai trouvé dans les commentaires de cette page, peu après le script fourni par Styx31 :

[quote]Posted by Frank Vanderhallen on August 4 2004 12:10pm

I’ve too much tables to execute the foreign key dependency checking script by hand. This little script does it all:

#!/bin/sh

check_constraints.sh

--------------------

Check foreign key contraints on MySQL database.

Written by Frank Vanderhallen, licensed under GPL.

if [ -z « $1 » ]
then
echo « \nUsage:\n\t./uname $0 [-h ] [-u user] [-p ]\n »
exit
fi

CONSTRAINTS=mysqldump $* | grep "CREATE\|CONSTRAINT" | sed 's/ /+/g'

for c in $CONSTRAINTS
do
if [ « echo $c | cut -d '+' -f 3 » = « CONSTRAINT » ]
then
CONSTRAINT=echo $c | cut -d '+' -f 4 | tr -d '\' CHILD_KEY=echo $c | cut -d ‹ + › -f 7 | tr -d '()`,' PARENT_TABLE=echo $c | cut -d ‹ + › -f 9 | tr -d '`' PARENT_KEY=echo $c | cut -d ‹ + › -f 10 | tr -d '()`,' QUERY="select c.$CHILD_KEY from $CHILD_TABLE as c left join $PARENT_TABLE as p on p.$PARENT_KEY=c.$CHILD_KEY where c.$CHILD_KEY is not null and p.$PARENT_KEY is null;" echo "Checking table '$CHILD_TABLE' constraint '$CONSTRAINT'" mysql -verbose $* -e "$QUERY" else CHILD_TABLE=echo $c | cut -d ‹ + › -f 3`
fi
done[/quote]

Certes, ce n’est toujours pas intégré à la base…

Ouais mais on avait deja vu tout ca, deneb :stuck_out_tongue:

Mais en fait, c’est plus un reproche que je fais a MySQL plus qu’une recherche de solution, du coup:
_Y a des transactions, mais au dump, elles ne sont pas gerees.
_Aucun systeme de verification d’integrite.

Et c’est le reproche que je fais a MySQL: etre parti d’un soft simple et vouloir en faire une vrai SGBD, avec les side effect de merde que ca engendre (le coup du dump qui se chie grave, c’est inadmissible a mon avis).

De plus, non seulement il faut analyser le dump pour refaire la restauration de la structure dans l’ordre, mais EN PLUS, il faut aussi classer les donnees de maniere a ce qu’elles s’inserent de maniere consistante.

Bref, j’espere que MySQL 5 est meilleur, et je devrais avoir a etudier le fonctionnement de PGSQL bientot pour pouvoir faire la difference (et essayer de me fendre d’un petit comparatif, tiens)

LoneWolf
Je pensais que MySQL, c’etait devenu mieux. Ben non. :stuck_out_tongue:

J’ai jamais vraiment utilisé innodb, mais pour ce que j’en sais, l’aspect transactionnel de la chose est censé empêcher la corruption des données.
Le cas de figure que tu décris n’est donc pas EN THEORIE censé se produire, je pense (du moins dans une base ou toutes les tables sont en innodb, parce que sinon, forcément, il y a risque).
A moins qu’un sauvage édite le dump, evidement :stuck_out_tongue:
Mais c’est en theorie. Et je n’ai pas d’expérience pour infirmer/confirmer.
Donc je pose la question : quelqu’un a t’il eu echo de la corruption d’une base innodb ?

A+

Non faut rester realiste, ca arrive regulierement avec leur systeme ne serais ce que parceque le courant a ete coupé pile poil au mauvais moment. Il y a que le backup complet qui soit safe dans ce cas la et encore il faut prevoir des strategies de multiples backups. Sans compter que les “transactions” de mysql ne sont pas journalisées donc si elles sont “atomiques” elle ne le sont que dans un monde ideal ou les threads ne crachent jamais ou le courant n’est jamais coupé, etc, etc. Me font marrer quand ils disent “full ACID compliance” mais bon c’est une autre histoire… sans compter que pour faire un backup d’une base innodb sans la tomber et sans mysqldump, c’est 390 euros par ordinateur que tu veux backuper.

En info si un truc “arrive jamais, les chances sont trop faibles, c’est impossible” tu peux etre certain que t’en as pour 10 minutes pour que ca arrive quelque part dans le monde avec ton produit. Murphy is king.

[quote name=‘GloP’ date=’ 6 Jan 2005, 11:33’]Ca arrive regulierement.
[right][post=“319493”]<{POST_SNAPBACK}>[/post][/right][/quote]

Ok.
Alors quel est l’interet de l’innodb par rapport à un myisam, s’il n’est pas fiable ?
A part les contraintes d’integrité (une facilité de dév qui peut être émulée par un peu plus de travail du coté applicatif) et le lock à la ligne (à l’interet moins evident)…
Les transactions ne serait donc que du vent ?
Pardon si mes questions parraissent stupides, mais vu que je n’ai jamais mis en oeuvre innodb, et que je m’interroge sur le fait de faire migrer mes bases sur ce format, je préfére poser des questions bêtes et avoir des réponses claires plutot que de ne pas les poser et rester dans l’expectative.

[edit suite à l’edit de Glop]
D’un autre coté, le problème hardware, le soft, il n’y peut pas grand chose.
C’est d’ailleur pour cela que le backup existe.
Et je ne savais pas que l’on devait tomber la base pour faire le backup avec innodb… m’en vais de ce pas voler aux nouvelles.
[/edit]

A+

[quote name=‹ fch › date=’ 6 Jan 2005, 02:41’]Ok.
Alors quel est l’interet de l’innodb par rapport à un myisam, s’il n’est pas fiable ?
A part les contraintes d’integrité (une facilité de dév qui peut être émulée par un peu plus de travail du coté applicatif) et le lock à la ligne (à l’interet moins evident)…[/quote]
Non non :stuck_out_tongue: Les contraintes d’integrite sont fondamentales et ont rien a voir avec une « facilite de dev ». C’est une componsente essentielle de toute base de donnee et « l’emuler » au niveau application, elle est la, la bidouille, pas l’inverse. C’est ta base qui sait tout sur elle meme, pas ton application, voires tes applications qui accedent chacun a un bout de data different mais en relation et qui sont pas forcement cense avoir acces a des infos qui doivent pourtant rester consistentes…

De meme le lock quel que soit son niveau (row, column, table, db) avec escalation et propagation, parfois cross db, est un concept carrement essentiel de toute base de donnee relationelle ou tu as pas le choix sur l’integrite. La gestion des conflits de locks, son influence sur le cache et autre ont d’ailleurs des influences majeures sur tous les produits a la peu des fesses qui se vendent en entreprise et c’est loin d’etre facile de bien comprendre les avantages et les defauts de chaque methode sur tes differentes couches applicatives.

Les transactions distribuees et leurs applications te permettent tout les jours d’etre sur que les sous que tu as sur ton compte disparaissent pas dans l’ether des flux financiers mondiaux B) meme en cas de foirage hardware, meme en cas de plantage systeme, meme en cas de « Simone la femme de menage enleve la prise pour brancher l’aspirateur dans le datacenter ».

Les interets du systeme, meme incomplet et pas 100% fiable de innodb, c’est « plus de fiabilite », « plus d’integrite ». Les differents niveaux dont tu as besoin de t’assurer dicte la somme que tu dois etre pret a depenser B) « plus fiable » c’est en general « plus cher »…

[quote]Les transactions ne serait donc que du vent ?
Pardon si mes questions parraissent stupides, mais vu que je n’ai jamais mis en oeuvre innodb, et que je m’interroge sur le fait de faire migrer mes bases sur ce format, je préfére poser des questions bêtes et avoir des réponses claires plutot que de ne pas les poser et rester dans l’expectative.[/quote]

Non pas du tout, pas du vent, faut pas tout jeter, c’est bien faut utiliser ce qu’on a au mieux pour ce qu’on y met. Et peut etre que ca satisfaira tes besoins a 100% et que tu es pret a dealer avec les consequences d’un truc qui chie parceque tu es pas un hopital ou une grande institution financiere. :stuck_out_tongue: C’est grave important de toujours faire « au mieux avec ce qu’on a » :stuck_out_tongue:

Mais il faut bien comprendre la difference entre les transactions offertes par mysql et celles offertes par d’autres db en depassant le pipo marketting des docs. Pour bien piger tout ca il faut saisir l’interet des transactions et ce qu’implique une db « ACID compliant » et pourquoi c’est necessaire et meme pas une option quand tu manipule autre chose que des datas pour lesquelles tu as aucun interet de consistence/integrite. Un forum, un site de news, un catalogue internet est un bon exemple.

[quote]D’un autre coté, le problème hardware, le soft, il n’y peut pas grand chose.
C’est d’ailleur pour cela que le backup existe.[/quote]
Si si il peut, il peut supporter les clusters sur plusieurs machines que ca soit pour les perfs, ou pour la fiabilite et la securite, tout en restant 100% transactionel, avec duplication temps reel, hot switch en cas de soucis et synchronisation auto quand tout revient dans l’ordre. La c’est couillu mais encore une fois: c’est pas gratuit mais ca fait la difference entre un systeme a un 9 et un systeme a 4, voire 5 :stuck_out_tongue: quand tu sais que des institutions brassent plusieurs centaines de milliards d’euros par an, meme ramené a 1 minute, ca fait beaucoup beaucoup de sous…

(edit/explication: 99% uptime → deux 9, 99.99% → quatre, 5 neufs, c’est moins de 5 minutes de downtime par an et c’est mega rare et mega ultra cher… pour un site web ca n’a absolument aucun sens meme si c’est google.com ou microsoft.com :stuck_out_tongue: Etre capable de passer de 3 a 4, voire 5, c’est un metier a part entiere qu’ont certaines personnes et une vraie specialité.)

Ok.
Donc si j’ai bien compris, innodb est un bon compromis technique entre un système hors de prix up 99,9999x9 du temps nécéssaire aux banques et au CEA, et le système à 0 F du mysql standard.
Pigé.
Mais vu que tu semble maitrisé le domaine, je creuse encore.
J’ai une base de données (evident), accédée par plusieurs utilisateurs simultanément susceptible de manipuler simultanément les mêmes données (bon, il y a peu de chances, mais murphy, tu le connait, apparament :stuck_out_tongue: ).
Ces données sont relativement sensibles et doivent être accessibles et cohérentes le plus souvent possible (bon, pas à 9 9 non plus :stuck_out_tongue: ).
La base peut être manipulée soit via une interface web, soit par service web, soit par le moulin à café de ma grand-mère (j’avais d’ailleur pas capté l’interet de l’intégrité référentielle pour ce cas de figure, merci :stuck_out_tongue: ).
Innodb me semble une bonne solution.
Cependant, je m’interroge sur la mise en oeuvre.
Il y a forcément utilisation des transactions et du lock au record pour garder l’intégrité, avec les start transaction, commit, select… for update|lock in share mode, etc…
Mais comment gérer la remonté d’erreur sur les contraintes d’intégrité avec un message d’erreur parlant pour l’utilisateur ?
Mettont une table B qui reference une table A avec la clef etrangere qui va bien.
Une solution que je vois est de commencer une transaction, faire le select … lock in share mode sur la table de reference A), vérifier que l’on a bien le record que l’on veut référencer, si pas, alors rollback et emission d’un message d’erreur « comprehensible » à l’utilisateur genre « Le contact n’a put être créé car son client de référence n’existe pas ou a été supprimé », sinon insertion dans B et commit.
Ai-je bon, ou me fourrage le doigt dans l’oeil ?

A+

[quote name=‘fch’ date=’ 6 Jan 2005, 14:33’]Ok.
Donc si j’ai bien compris, innodb est un bon compromis technique entre un système hors de prix up 99,9999x9 du temps nécéssaire aux banques et au CEA, et le système à 0 F du mysql standard.
[…]
Cependant, je m’interroge sur la mise en oeuvre.
Il y a forcément utilisation des transactions et du lock au record pour garder l’intégrité, avec les start transaction, commit, select… for update|lock in share mode, etc…
Mais comment gérer la remonté d’erreur sur les contraintes d’intégrité avec un message d’erreur parlant pour l’utilisateur ?
[right][post=“319573”]<{POST_SNAPBACK}>[/post][/right][/quote]

hop:
http://sqlpro.developpez.com/cours/sqlaz/techniques/ puis recherche le mot mysql dans le texte

[quote name=‘phili_b’ date=’ 6 Jan 2005, 17:15’]hop:
http://sqlpro.developpez.com/cours/sqlaz/techniques/ puis recherche le mot mysql dans le texte
[right][post=“319625”]<{POST_SNAPBACK}>[/post][/right][/quote]

Mouais.
Ca cause pas des masses innoDb/integrité/integration utilisateur, tout cela.
Vouloir démontrer que Mysql n’est pas le meilleur des meilleurs et qu’il n’est pas réellement un SGBD, ca m’aide pas.
Par contre, les autres articles sont vraiment très bien et interessant.
Merci pour le lien.