Vous n'êtes pas identifié(e).

#1 02/07/2012 12:48:42

gglamenace
Membre

INSERT et accès concurrentiel

Bonjour,

je désire faire un insert à partir d'une procédure stockée en récupérant le dernier index de ligne de la table (champ auto incrémenté), l'incrémenter de 1 et utiliser ce nombre pour remplir un autre champ.
Si tout se passe bien POSTGRESQL fera l'insert en incrémentant de lui-meme l'index et du coup le champ calculé à partir de l'index sera cohérent.

Mon problème est que je ne suis pas certain qu'entre le moment où je récupère le dernier index et le moment où je fais l'INSERT, un autre INSERT n'aura pas déjà incrémenté l'index et donc l'INSERT que je fais dans ma procédure produira une ligne avec un index qui n'est pas celui utilisé pour remplir un autre champ.

Pouvez-vous me donner la bonne pratique pour ne pas avoir ce genre de problème?
Je ne sais pas si je peux utiliser un TRIGGER AFTER ou autre.

Si vous pouvez m'éclairer...

Merci
Jérôme

Hors ligne

#2 02/07/2012 15:13:04

Marc Cousin
Membre

Re : INSERT et accès concurrentiel

Le mieux, en théorie, c'est de ne pas le faire: vous risquez d'avoir des problèmes de concurrence très importants (vous allez sérialiser les insertions dans cette table). Donc d'utiliser des séquences et d'accepter les trous.

Sinon, le «deuxième mieux», c'est d'avoir un enregistrement dans une table externe, qui sera verrouillé pour faire la «séquence».

Quelque chose du genre:

BEGIN;

UPDATE table_sequence SET valeur=valeur+1 where cle=cle_table_principale RETURNING valeur

INSERT INTO ma_table_principale xxxxxxxx (dont la valeur récupéréé).

COMMIT;

L'update, fait comme ça, empêche tout autre update de l'enregistrement tant que votre opération à vous n'a pas réussi ou échoué. Évidemment, si vous avez un gros traitement entre l'update sur la table de séquence et le commit, pendant ce temps là, personne d'autre ne peut faire d'update. C'est pour ça que dans la mesure du possible, on accepte d'avoir des séquences «à trou» (sauf pour des factures ou autre besoin fonctionnel de ce genre, où c'est une obligation de ne pas avoir de trou).


Marc.

Hors ligne

#3 02/07/2012 15:14:46

gleu
Administrateur

Re : INSERT et accès concurrentiel

Utilisez une séquence, c'est fait pour ça. Voir http://docs.postgresql.fr/9.1/sql-createsequence.html pour les détails.


Guillaume.

Hors ligne

#4 02/07/2012 15:42:28

gglamenace
Membre

Re : INSERT et accès concurrentiel

gleu a écrit :

Utilisez une séquence, c'est fait pour ça. Voir http://docs.postgresql.fr/9.1/sql-createsequence.html pour les détails.

Bonjour,

j'avais pensé utiliser les sequences pour que ce soit POSTGRESQL qui me fournisse la valeur calculée en automatique, mais avec les sequences on ne peut générer que des nombres.
Dans mon cas je veux remplir un champ en convertissant l'index de la ligne en base64.
J'ai trouvé ceci comme doc pour utiliser du PL/SQL en tant que trigger:
http://www.postgresql.org/docs/9.1/inte … igger.html

Je pense que le trigger AFTER INSERT et l'utilisation de l'objet NEW pour avoir récupérer la valeur de l'index et pouvoir faire un update du champ dans lequel je stocke en base64 l'index me permettra de garder la cohérence entre l'index et le champ contenant l'index en base64.

Ca fait malheureusement un INSERT puis un UPDATE, mais je ne vois pas d'autre solution.

Qu'en pensez-vous?


Jérôme

Hors ligne

#5 02/07/2012 23:15:33

gleu
Administrateur

Re : INSERT et accès concurrentiel

Le problème que vous allez rapidement rencontré, c'est que votre trigger ne fonctionnera pas si vous ne verrouillez pas en écriture la table le temps de faire votre insertion. Et là, les performances vont devenir ridicules.

Le mieux serait d'expliquer pourquoi vous ne pouvez pas passer par une séquence, histoire de trouver une solution passant par une séquence smile


Guillaume.

Hors ligne

#6 02/07/2012 23:25:47

gglamenace
Membre

Re : INSERT et accès concurrentiel

J'ai une table avec 3 champs:
index (entier auto incrémenté)
index_base64 varchar(10)
URL varchar(200)
je voudrais à chaque INSERT que le champ index soit auto incrémenté par POSTGRESQL, que je remplisse le champ URL et que le champ index_base64 soit calculé en prenant index et en le transposant en base64.

Quelle serait selon vous la meilleur solution?

Merci d'avance pour votre aide.

Jérôme

Dernière modification par gglamenace (02/07/2012 23:26:02)

Hors ligne

#7 02/07/2012 23:45:20

gglamenace
Membre

Re : INSERT et accès concurrentiel

J'ai aussi pensé à utilisé now pour le champ index qui me donne date et heure avec les microsecondes et utiliser la date/heure et le convertir en base64.
Qu'en pensez-vous?

Dernière modification par gglamenace (02/07/2012 23:46:01)

Hors ligne

#8 03/07/2012 10:21:59

gleu
Administrateur

Re : INSERT et accès concurrentiel

Le champ index étant un entier, une séquence me paraît la meilleure solution.

Quant à now(), je ne vois pas en quoi cela change le problème. Il existe toujours une possibilité que vous ayez deux mêmes dates et heures.


Guillaume.

Hors ligne

#9 03/07/2012 10:25:37

flo
Membre

Re : INSERT et accès concurrentiel

Personnellement, je pense que tout cela est bien compliqué et surtout je ne comprends absolument pas votre besoin de "convertir" l'index en base64, et de le stocker. Si l'index_base64 est calculé à partir de l'index, il vaut mieux ne pas stocker les 2 (vous n'êtes pas en première forme normale dans ce cas...)
Pourriez-vous expliquer ce que vous voulez faire réellement? À quoi sert tout ce micmac?

Hors ligne

#10 04/07/2012 18:12:23

gglamenace
Membre

Re : INSERT et accès concurrentiel

Merci pour vos réponses,
je vais effectivement ne pas stocker la valeur en base64 et la calculer à la voler!



flo a écrit :

Personnellement, je pense que tout cela est bien compliqué et surtout je ne comprends absolument pas votre besoin de "convertir" l'index en base64, et de le stocker. Si l'index_base64 est calculé à partir de l'index, il vaut mieux ne pas stocker les 2 (vous n'êtes pas en première forme normale dans ce cas...)
Pourriez-vous expliquer ce que vous voulez faire réellement? À quoi sert tout ce micmac?

Hors ligne

Pied de page des forums