|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||||
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Bonjour,
J'ai un type composite que je voudrais utilisé en clé primaire. Code :
Code :
Si qlq pourrait m'aidez... Par ailleurs, "Num" devrait être gerer par une sequence réinitialisée en début d'année. Un trigger ferait-il l'affaire ? là aussi un peu d'aide serait la bien venue... Merci d'avance. |
||||
|
|
00
|
|
|
#2 | ||
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Cela me semble inutile mais pour info voici la définition de mes DOMAIN annee et mois...
Code :
Merci d'avance. |
||
|
|
00
|
|
|
#3 |
|
Membre émérite
![]() ![]() Inscription : mars 2002 Messages : 770 ![]() |
Bonjour,
en fait pour creer un index sur une clef composite implique que pg doit comprendre comment indexer les données de ce type, je m'explique comment pg va determiner que : 2008::annee 2::mois 7::int est au plus grand que 2008::annee 12::mois 3::int ? il faut donc déterminer le comportement de ton type en créant : CREATE OR REPLACE FUNCTION super_idlt(super_id, super_id) .... .... pour < CREATE OR REPLACE FUNCTION super_idgt(super_id, super_id) .... .... pour > .... CREATE OR REPLACE FUNCTION btsuper_idcmp(super_id,super_id) RETURNS super_id AS .... ... pour le btree ... apres les classes d'operateur : CREATE OPERATOR CLASS super_id_ops DEFAULT FOR TYPE super_id USING btree AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 btsuper_idcmp(super_id, super_id), enfin un truc dans le genre |
|
|
00
|
|
|
#4 |
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Merci bcp pour la réponse rapide...
Mais ça à l'air quand même assez complexe, je vais voir si je ne peux pas gerer tout cela autrement. |
|
|
00
|
|
|
#5 | ||||
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Volià après qlq réflexion j'ai trouvé ue autre methode pour faire ce que je veux...
Au lieu du type composite super_id j'ai testé avec un BIGINT que je construit moi même, je m'explique. Le but est d'avoir un un numéro de vente sous la forme AAAMM999999, par ex 200807000214 Donc une colonne vente_id en BIGINT, une sequence pour le numéro et un TRIGGER BEFORE INSERT qui construit tout ça et qui réinitialise la sequence pour la 1ère vente de l'année. Code :
Code :
J'ai testé avec currval('vente_id_seq')+1 dans le TRIGGER BEFORE INSERT et nextval('vente_id_seq') dans un TRIGGER AFTER INSERT mais ça ne fonctionne pas, au currval erreur "la sequence n'est pas initialisée dans cette sesson". Plusieures questions : 1. Si je n'utilise pas de sequence mais que j'extrait le numéro de la dernière vente et que je l'incremente dans le TRIGGER BEFORE INSERT, dans une utilsation multi-utilisateur est ce que je n'aurais pas de problème de doublons ? 2.Comment puis-je me faire une fonction independante (calc_id(table) ou calc_id(table, sequence)) du trigger qui prendrait en paramètre la table ou son nom et eventuellement la sequence ou son nom et puis je ferais un trigger différent pour chaque table qui appelerait la fonction avec différents paramètres. Ou si vous savez une autre idée merci d'avance. |
||||
|
|
00
|
|
|
#6 | ||
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Voici le résultat de mes recherches...
Je gère tout moi même...pas de séquence parce que si l'INSERT échoue la sequence est quand même incrémentée et que je veux pas de trous dans mes n°... ça fonctionne nickel mais pour les accès concurents... Code sql :
...pour tester les accès concurents je me suis fais un petit programme(que je lance plusieur fois) en java avec une boucle d'INSERT massif. Mais j'ai dû mettre un Code sql :
LOCK TABLE ventes IN EXCLUSIVE MODE Cela fonctionne exactement comme je veux mais je n'aime pas utilisé le LOCK...pas portable et un peu "trop". D'après la doc de PostgreSQL on devrait pouvoir faire la même chose avec SET TRANSACTION mais je ne vois pas comment... Si qlq a une idée avec SET TRANSACTION je suis preneur... Merci d'avance. |
||
|
|
00
|
|
|
#7 |
![]() ![]() ![]() Frédéric BROUARDExpert SGBDR & SQL Inscription : mai 2002 Messages : 10 959 ![]() |
SET TRANSACTION faite partie de la norme SQL.
Lisez ce que j'ai écrit à ce sujet : http://sqlpro.developpez.com/cours/s...chniques/#L1.3 A +
__________________
Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL Site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/ Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp. Blog SQL, SQL Server, modélisation données : http://blog.developpez.com/sqlpro http://www.sqlspot.com : modélisation, conseils, audit, optimisation, formation * * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * * |
|
00
|
|
|
#8 |
|
Membre confirmé
![]() Inscription : janvier 2006 Messages : 178 ![]() |
LOCK TABLE en mode EXCLUSIVE est effectivement trop contraignant car tu vas bloquer toutes les modifs sur la table alors que tu ne veux fonctionnellement que bloquer les autres insertions potentielles (qui vont devoir générer aussi un ID).
De plus, MAX est une opération qui peut être coûteuse sur une grande table, même si on peut l'optimiser avec un index. Bref, je te proposes plutôt une autre solution : - Crée une autre table ventes_id avec une colonne Annee et une colonne Numero, toutes deux des entiers. Je propose Annee puisque tu numérotes de façon unique par année. - Pour chaque nouvelle vente tu fais un SELECT FOR UPDATE sur ventes_id pour l'année en cours, en récupérant la colonne Numero - Tu construis ton nouvel ID, tu insères ta nouvelle vente puis tu viens faire un UPDATE sur ventes_id pour incrémenter Numero - Tu commit, ce qui libères le verrou posé par SELECT FOR UPDATE Ainsi tu ne verrouilles jamais la table ventes mais tu verrouilles fonctionnellement les insertions entre elles. De plus, la récupération du numéro est beaucoup plus rapide et moins gourmande qu'avec le MAX HTH |
|
|
00
|
|
|
#9 | ||||
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Merci pour remarques. J'ai encore fait qlq modifications mineures et aussi fais qlq test de performance puisque rbaraer me met en garde sur le "cout" de MAX (qui est fait sur vente_id BIGINT PRIMARY KEY).
L'idée de devoir passer par une table de plus ne me plaisant pas voici ce que je vais certainement utilisé au final... J'utilise maintenant LOCK TABLE ventes IN SHARE UPDATE EXCLUSIVE MODE dans le TRIGGER et pas dans le programme Java, ce qui est moins restrictif que le EXCLUSIVE MODE...si j'ai bien compris la doc PG... L'exemple porte sur une table de ventes mais je vais utiliser la même technique pour différentes tables (envois, receptions, commandes, livraisons, etc...) Donc d'abord une FUNCTION qui sera utlisée dans tous les TRIGGER. Code sql :
el le TRIGGER BEFORE INSERT sur table ventes Code sql :
Quand au performances, avec qlq valeurs de test, l'INSERT de 50000 ventes ce fait en 36 sec sur une table vide, 37 sec sur une table contenant 500000 ventes et 38 sec sur une table contenant 1000000 de ventes... Cela me convient parfaitement... |
||||
|
|
00
|
|
|
#10 |
|
Membre du Club
![]() Inscription : janvier 2008 Messages : 121 ![]() |
Précision sur les performances...en accès concurents
5 processus lancer en même temps qui créent 20000 ventes chacuns 5min08sec sur une table vide, puis 5min32sec sur une table contenant 100000 ventes et 5min54sec sur une table contenant 200000 ventes... |
|
|
00
|
Copyright © 2000-2012 - www.developpez.com