IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes PostgreSQL Discussion :

Fonction exécutée une seule fois dans un update


Sujet :

Requêtes PostgreSQL

  1. #1
    Invité
    Invité(e)
    Par défaut Fonction exécutée une seule fois dans un update
    Bonsoir à tous,

    J'ai une fonction qui construit une chaine aléatoire (génère_clé_str)
    Si j'appelle cette fonction par un trigger tout se passe comme prévu et j'ai les données que j'attends.
    Par contre si je fais un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    UPDATE
    classements
    SET
    clé=(SELECT génère_clé_str())
    ;
    J'ai une valeur unique pour tous les enregistrements !
    J'ai essayé de mettre un WHERE => Rien changé
    Ma fonction est bien "VOLATILE"

    Bref, je suis dans la mouise...

    Quelqu'un aurait-il une idée ?

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 736
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 736
    Points : 52 448
    Points
    52 448
    Billets dans le blog
    5
    Par défaut
    C'est normal. L'optimisation des requêtes consiste à ne pas ré exécuter des opérations dont le résultat doit toujours être le même. En conséquence, votre fonction n'est appelée qu'une seule fois pour être appliquée à toutes les lignes (comportement ensembliste).
    Il est d'autant plus stupide d'utiliser un tel type de fonction que PG possède deux mécanismes différents parfaitement intégrés pour des clefs aléatoires :
    1) l'auto incrémentation avec le type SERIAL;
    2) l'utilisation de UUID (ou GUID) avec la fonction uuid_generate_v4().

    Pourquoi donc vouloir réinventer la roue en moins bon et moins performant ?

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    Sur l'UPDATE à proprement parler, le problème est que rien n'indique au SQL que tu veux obtenir telle valeur pour telle ligne puisqu'il n'y a aucune clause WHERE ni aucune corrélation. L'interpréteur SQL choisit la donc la solution la plus efficace avec un seul appel de fonction, peu importe qu'elle soit VOLATILE ou pas.

    Mais de toute manière si la colonne clé est censée être une clef unique, effectivement lui mettre une valeur aléatoire est incorrect puisque c'est compter sur la chance pour éviter les doublons. Il faut utiliser un vrai générateur unique.

    Si le but est d'avoir une clef unique mais qui ait l'air aléatoire, il faut utiliser un algorithme qui fasse ça, par exemple une colonne SERIAL transformée avec pseudo_encrypt puis passée à une fonction qui l'exprime en chaine de caractères avec un certain alphabet à décider par le programmeur. Et cette fonction peut ajouter des caractères aléatoires pour agrandir la chaine si nécessaire.

    C'est typiquement le genre d'algorithme qui est utilisé pour la génération de numéros de coupons uniques personnalisés pour des opérations de promo, ou encore des réducteurs d'URLs.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Merci messieurs pour vos contributions.

    Petite remarque à l'attention de SQLPro : Nous verrons si la solution est "stupide" uniquement à la fin de la discussion et uniquement si une solution est trouvée. En attendant, l'humilité devrait vous guider vers un peu plus de modération dans vos propos.

    Mon soucis est de générer une clé à des fins cryptographiques. Il me faut donc une longue clé (100 caractères = longueur max de la chaîne en clair) afin de créer de l'entropie. Les types SERIAL, BIGSERIAL et UUID sont donc trop courts. Elle n'a pas nécessité d'être unique même si c'est éminemment souhaitable pour compliquer la cryptanalyse.

    Je me sers d'une fonction "maison" qui ressemble à la pseudo_encrypt.

    Mais je pense que la question n'est pas là car même si je mettais au point la meilleure fonction, je resterais dans l'incapacité de générer des valeurs différentes lors de l'appel de mon UPDATE !
    L'instruction VOLATILE devrait m'assurer le ré-appel de cette fonction nonobstant les mécanismes d'optimisation.
    Dernière modification par ced ; 10/12/2012 à 12h47.

  5. #5
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    Et en modifiant la fonction pour qu'elle prenne un paramètre en entrée, à appeler comme ci-dessous ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    UPDATE classements
       SET clé=(SELECT génère_clé_str(id_pk))
    Sinon il faut faire une boucle et un update ligne à ligne comme le fait le trigger

  6. #6
    Invité
    Invité(e)
    Par défaut
    Merci skuatamad mais j'ai déjà tenté le coup.
    Sous une autre forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Clé=(SELECT génère_clé_str('test',random()))
    Et pour info, cela fonctionne convenablement sous mysql.
    Je vais quand même faire le test avec ta proposition.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Et il le fallait !
    Ca fonctionne.
    Merci.

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 736
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 736
    Points : 52 448
    Points
    52 448
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par nenex73 Voir le message
    ...

    Mon soucis est de générer une clé à des fin cryptographique. Il me faut donc une longue clé (100 caractères = longueur max de la chaîne en clair) afin de créer de l'entropie. les types SERIAL, BIGSERIAL et UUID sont donc trop courts. ...
    Il suffit d'utiliser n fois la fonctions générant des UUID en les concaténant !

    Testez donc ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT CAST(uuid_generate_v4() AS VARBINARY(16)) + CAST(uuid_generate_v4() AS VARBINARY(16)) + CAST(uuid_generate_v4() AS VARBINARY(16))
    Je pense que cela ira beaucoup plus vite et vous fournira une clef de 48 octets. Si cela ne suffit pas, passez au double...

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  9. #9
    Invité
    Invité(e)
    Par défaut
    @ SQLPro.

    Votre solution ne convient pas car elle laisse une empreinte trop prononcée. En effet, si mes souvenirs sont bons, la fonction UUID() va générer des chaines différentes mais très semblables.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT UUID()
    UNION
    SELECT UUID()
    =>
    3e5dca58-3e0b-11e2-b63b-3860772eae56
    3e5dcaa8-3e0b-11e2-b63b-3860772eae56

    Une seule lettre d'écart !
    Pour créer de l'entropie à des fins cryptographiques, c'est vraiment pas terrible !
    Dernière modification par ced ; 10/12/2012 à 12h50. Motif: Merci d'utiliser la balise [CODE] (bouton #)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Fonction à appliquer une seule fois dans un laps de temps
    Par rvm31 dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 26/06/2015, 02h07
  2. Réponses: 6
    Dernier message: 08/08/2011, 02h07
  3. Réponses: 6
    Dernier message: 23/05/2008, 00h15
  4. Ma requete s'execute qu'une seule fois dans mon curseur
    Par remyescof dans le forum Développement
    Réponses: 5
    Dernier message: 21/03/2008, 10h03
  5. executer fonction javascript une seule fois sur un onchange
    Par sebdu dans le forum Général JavaScript
    Réponses: 13
    Dernier message: 24/08/2007, 15h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo