Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 6 sur 6
  1. #1
    Invité de passage
    Inscrit en
    février 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : février 2008
    Messages : 9
    Points : 0
    Points
    0

    Par défaut optimisation "UPDATE <> WHERE ID IN (SELECT <> )"

    Bonjour,
    J'utilise pas mal de requête du genre :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    UPDATE MATABLE1 T1
    SET T1.FIELD = "QQC"
    WHERE T1.ID IN
    (
    SELECT T2.ID
    FROM MATABLE1 T2
    JOIN MATABLE2 T3
    ON T2.ID = T3.T2ID
    WHERE <conditions plus ou moins complexe...>
    )
    En fait, de souvenir, je passe par là car je suis en Firebird 2.1 et le moteur n'accepte pas de faire des UPDATE sur plusieurs tables:
    Code :
    1
    2
    3
    UPDATE MATBLE1 T1,MATABLE2 T2
    SET T1.FIELD = "QQC"
    WHERE T1.F1 =... AND T2.F3 = ....
    Ou même en passant par des JOIN au niveau de l'UPDATE, il rejette la requête

    Le truc c'est qu'en passant par une sous-requête et en faisant WHERE ID IN (liste ID résultat d'une requête)
    J'ai l'impression, en fait vu les statistique du résultat, c'est pas qu'une impression, qu'il exécute la sous-requête autant de fois qu'elle ne contient de résultat. Du coup, le temps d'exécution est énorme et est proportionnel au nombre de resultat de sou-requête.
    Actuellement j'arrive à optimiser manuellement en exécutant la sous-requête, en copiant les résultats en y insérant une virgule et j'exécute l'UPDATE avec la liste des ID copiés.
    Code :
    1
    2
    3
    4
    UPDATE MATABLE1 T1
    SET T1.FIELD = "QQC"
    WHERE T1.ID IN
    (234234,46573,23545,24567,5674578,65463,245654,....)
    Efficace, mais laborieux :o/

    N'y a-t-il pas un autre moyen pour faire ce genre de chose ?
    Merci d'avance

    Hervé

    [EDIT] oublié le IN dans WHERE

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

    Par défaut

    Je l'écrirais plutôt comme ça, inutile de repasser sur matable1 :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    UPDATE MATABLE1 T1
       SET T1.FIELD = 'QQC'
     WHERE EXISTS (SELECT 1
                     FROM MATABLE2 T3
                    WHERE T1.ID = T3.T2ID
                      AND <conditions plus ou moins complexe...>
                  )
       AND <autres conditions>
    Sinon il est également possible d'utiliser MERGE en ne précisant que la clause WHEN MATCHED, surtout utile quand la nouvelle valeur (ici QQC) provient d'une requête sur la table matable2.

    [EDIT] Au fait je ne connais pas firebird, la doc sur merge concerne la 2.5, je ne sais pas si le fonctionnement est identique en 2.1

  3. #3
    Invité de passage
    Inscrit en
    février 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : février 2008
    Messages : 9
    Points : 0
    Points
    0

    Par défaut

    Merci skuatamad
    Je vais essayer ça.
    Effectivement, tu fais bien de préciser, j'ai l'impression que Firebird est en évolution perpétuelle, à la mode JAVA, du coup, suivant les versions, il y a des choses disponibles, d'autres non, d'autres plus...

  4. #4
    Invité de passage
    Inscrit en
    février 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : février 2008
    Messages : 9
    Points : 0
    Points
    0

    Par défaut

    Je ne vois pas très bien le fonctionnement du SELECT 1 ?
    Tu pourrais expliciter ?
    Merci

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

    Par défaut

    Avec EXISTS il n'est pas nécessaire de sélectionner des colonnes dans la sous-requête : EXISTS and SINGULAR
    The EXISTS predicate returns true if the result set of the subselect contains at least one row. If it is empty, EXISTS returns false.
    Moi j'utilise 1 dans la sous-requête, d'autres NULL ou 'X', ou encore * mais je n'aime pas * qui fait un appel au dictionnaire (en tout cas il me semble que c'est vrai sur Oracle).

    Et puis 1 ou NULL montre bien que la logique n'est pas dans les colonnes sélectionnées mais dans la corrélation entre les 2 requêtes.

    Sinon tu peux aussi utiliser IN :
    Code :
    1
    2
    3
    4
    UPDATE MATABLE1 T1
       SET T1.FIELD = 'QQC'
     WHERE T1.ID IN (SELECT T3.T2ID FROM MATABLE2 T3 WHERE <conditions plus ou moins complexe...>)
       AND <autres conditions>

  6. #6
    Invité de passage
    Inscrit en
    février 2008
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : février 2008
    Messages : 9
    Points : 0
    Points
    0

    Par défaut

    Alors, désolé, j'avais oublié le IN dans la première requête de mon post.
    J'utilise actuellement la méthode du WHERE T1.ID IN(SELECT. . . )
    Et c'est justement l'objet de mon post car cette méthode prend énormément de temps car il semble que le moteur Firebird exécute la sous-requête autant de fois que le nombre de résultat de cette sous-requête, enfin c'est une supposition.
    Mais plus il y a de résultats, plus ça prend des plombe.
    Je vais essayer ton autre solution.

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
  •