Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 9 sur 9
  1. #1
    Nouveau Membre du Club
    Inscrit en
    octobre 2007
    Messages
    58
    Détails du profil
    Informations forums :
    Inscription : octobre 2007
    Messages : 58
    Points : 30
    Points
    30

    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 :
    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 Frédéric BROUARD
    Expert SGBDR & SQL
    Inscrit en
    mai 2002
    Messages
    13 362
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric BROUARD
    Localisation : France

    Informations professionnelles :
    Activité : Expert SGBDR & SQL
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 13 362
    Points : 27 472
    Points
    27 472

    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
    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 * * * * *

  3. #3
    Expert Confirmé
    Profil pro
    Inscrit en
    octobre 2008
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 822
    Points : 2 517
    Points
    2 517

    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
    Nouveau Membre du Club
    Inscrit en
    octobre 2007
    Messages
    58
    Détails du profil
    Informations forums :
    Inscription : octobre 2007
    Messages : 58
    Points : 30
    Points
    30

    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.

  5. #5
    Expert Confirmé
    Inscrit en
    août 2008
    Messages
    2 146
    Détails du profil
    Informations forums :
    Inscription : août 2008
    Messages : 2 146
    Points : 3 745
    Points
    3 745

    Par défaut

    Et en modifiant la fonction pour qu'elle prenne un paramètre en entrée, à appeler comme ci-dessous ?
    Code :
    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
    Nouveau Membre du Club
    Inscrit en
    octobre 2007
    Messages
    58
    Détails du profil
    Informations forums :
    Inscription : octobre 2007
    Messages : 58
    Points : 30
    Points
    30

    Par défaut

    Merci skuatamad mais j'ai déjà tenté le coup.
    Sous une autre forme :
    Code :
    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
    Nouveau Membre du Club
    Inscrit en
    octobre 2007
    Messages
    58
    Détails du profil
    Informations forums :
    Inscription : octobre 2007
    Messages : 58
    Points : 30
    Points
    30

    Par défaut

    Et il le fallait !
    Ca fonctionne.
    Merci.

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro Frédéric BROUARD
    Expert SGBDR & SQL
    Inscrit en
    mai 2002
    Messages
    13 362
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric BROUARD
    Localisation : France

    Informations professionnelles :
    Activité : Expert SGBDR & SQL
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 13 362
    Points : 27 472
    Points
    27 472

    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 :
    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
    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 * * * * *

  9. #9
    Nouveau Membre du Club
    Inscrit en
    octobre 2007
    Messages
    58
    Détails du profil
    Informations forums :
    Inscription : octobre 2007
    Messages : 58
    Points : 30
    Points
    30

    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 :
    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 !

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •