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

MS SQL Server Discussion :

Efficacite de CASE dans un UPDATE ?


Sujet :

MS SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Janvier 2005
    Messages
    61
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 61
    Par défaut Efficacite de CASE dans un UPDATE ?
    Bonjour a tous,

    en fouillant rapidement les possibilites de transact-sql (il y en a quand meme pas mal et on en oublie souvent), je suis tombe sur CASE que je n'avais jusqu'a present jamais utilise.

    Or nous avons dans un jeu, une table definissant la liste des "items" possedes par les personnages, avec pour chaque item une ligne de la forme :
    - le nom du personnage qui possede
    - l'index de l'objet dans l'inventaire du personnage
    - le nombre d'utilisations restantes
    - le Status de l'objet (0 indisponible, 1 dans l'inventaire...)

    On utilise beaucoup ce Status, et donc lorsqu'un joueur utilise un Item, on commence par reduire le nombre d'utilisations restantes par un update, puis si ce nombre devient nul, on fait un nouvel update pour rendre l'objet indisponible (requete de la forme suivante en gros) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    UPDATE tblObjets SET Restant = Restant - 1 WHERE Perso = @lePerso AND Index=@indexObjet AND Status <> 0
    UPDATE tblObjets SET Status = 0 WHERE Restant = 0 Perso = @lePerso AND Index=@indexObjet AND Status <> 0
    Mon idee serait donc de reunir tout ca sous une seule requete, qui update les 2 nombres a la fois (si le nombre restant est 1, on sait qu'il finira a 0 apres l'update et donc, on place le status a 0 aussi car l'objet devient inutilisable)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UPDATE tblObjets SET Status = CASE WHEN Restant = 1 THEN 0 ELSE 1 END, Restant = Restant - 1 WHERE Perso = @lePerso AND Index=@indexObjet AND Status <> 0
    (J'espere que les exemples de code sont clairs)

    Voila donc le concept. Mais mon collegue pense que l'utilisation de CASE ralentit trop le process et serait en realite plus lent que faire les 2 update a la suite, ce dont je ne suis pas du tout certain. Du coup, j'aurais aime savoir ce qui selon vous (par experience si possible ^^) est le plus rapide et efficace : avec ou sans CASE ?

    Merci d'avance.

    ps: oui je sais, on pourrait supprimer Status et juste utiliser "Restant" pour tester la dispo ou pas de l'item (si different de 0, hop l'item est dispo nickel), mais il se trouve que ce n'est pas possible dans la majorite des cas car status a plus de 2 valeurs dans le cas reel, donc une reelle signification plus que binaire ^_^

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 298
    Par défaut Juste un raisonnement
    Pour ce que ça vaut, car je ne connais pas le SGBD.

    Faire 2 update implique de lire 2 fois la même table.

    AMHA, avec le CASE, on doit ralentir légèrement le traitement car le moteur SQL doit effectuer le test, mais en revanche on ne lit qu'une seule fois la table, donc on doit en final gagner du temps.


  3. #3
    Membre averti
    Inscrit en
    Janvier 2005
    Messages
    61
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 61
    Par défaut
    C'est aussi ce que je pense. Et c'est un peu ce que la simple logique aurait tendance a dicter, car une fois la ligne lue, le traitement pour le Case ne semble pas tres lourd.

    Toutefois mon collegue me soutient que le CASE est relativement lourd a traiter pour le serveur et qu'il vaut mieux l'eviter. C'est aussi possible si ca sort des attributions classiques des fonctions de base internes au serveur, mais pour ca je n'ai pas vraiment de moyen de verifier a part chercher l'experience la ou elle se trouve... ici (enfin il me semble ^_^).

    Du coup si quelqu'un a une idee sur cet epineux probleme d'optimisation, je suis preneur.

    ps: merci Mercure pour la reponse, je commencais a m'inquieter avec 2 sujets basiques et clairs sans aucune reponse ..

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 298
    Par défaut Test de 2 requêtes
    Je ferais alors un test de perf. sur chaque requête, de nuit pour ne pas perturber les traitements de journée.

    Sur un échantillon bien représentatif des données, voire sur l'ensemble de la table, je mesurerais programmatiquement le temps que SQL passe (durée et CPU) à faire les 2 updates puis le temps qu'il passe à faire la requête avec CASE.
    Je comparerais ensuite les résultats et je serais fixé.

    Ces tests me permettraient ainsi de confirmer l'hypothèse probable du gain de temps auprès de mon collègue ou au contraire de l'infirmer.

  5. #5
    Membre confirmé Avatar de neuropathie
    Inscrit en
    Janvier 2005
    Messages
    223
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 223
    Par défaut
    Selon les best practices et les retours d'expériences que j'ai pu consulter, l'instruction UPDATE est lourde et est à éviter pour les applis web, par contre pour les clients riches elle est utile. donc un UPDATE avec le CASE, je crois que c'est déconseillé

  6. #6
    Membre chevronné Avatar de Rei Angelus
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2006
    Messages
    292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2006
    Messages : 292
    Par défaut
    Je travaille sur SYBASE et j'utilise régulièrement le 'CASE'. Cependant, cela me pose régulièrement des problèmes de temps de traitement qui m'obligent à revenir à des requêtes simples (si possible).

    A mon avis les 2 UPDATE seront beaucoup plus rapides que le UPDATE CASE.

    Après effectivement, il est judicieux de faire des tests avec ton SGBD et ta base pour en avoir confirmation.

  7. #7
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Par défaut
    Citation Envoyé par k'n1
    Mais mon collegue pense que l'utilisation de CASE ralentit trop le process
    Dans la plupart des SGBD, l'utilisation d'un CASE dans une jointure ralentit énormément le temps d'exécution de la requête puisque le SGBD ne peut plus alors se baser sur les index des tables.

    Hors d'une jointure, l'exécution est ralentie, mais dans une moindre mesure (2 UPDATE risquent tout de même d'être plus rapides).

    Il y a sûrement quelque chose à améliorer dans le modèle pour garantir qu'à tout moment, on ait bien Restant = 0 -> Statut = 0 sans devoir le spécifier pour chaque fois (par une vue, par exemple).
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 120
    Par défaut
    A titre personnel je proscrirais le Case dans un update au même titre qu'un OR dans les trois quart des ordres SQL que je remplace fort volontier par un Union dès que cela est possible ...

    D'un point de vue physique le case va empecher d'utiliser les index (sauf si tu fais un index fonction ... auquel cas il faudrait rechercher un peu plus loin) et donc faire un fetch complet de ta table pour faire les update.

    Deux updates bien placés sur des clés seront donc beaucoup plus efficaces à mon avis !

  9. #9
    Membre averti
    Inscrit en
    Janvier 2005
    Messages
    61
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 61
    Par défaut
    pcaboche, scornille > merci pour vos reponses qui se rejoignent.

    Toutefois, je ne comprend pas pourquoi l'utilisation des index est impossible lors de l'utilisation du CASE, tout du moins dans le cas present, ni pourquoi il faudrait faire 2 fetch de la table ?

    dans l'exemple cite, la table a un index sur 'Perso' et 'Index' il me semble. On voit que ces 2 elements se trouvent bien dans la clause Where donc pas de soucis. Par contre, on n'utilise pas de case du le 'Status' car il a tendance a pas mal changer, ce qui ralentirait pas mal l'utilisation de la table.

    De plus, l'element sur lequel porte le CASE est un element du tuple sur lequel on travail (en l'occurence, toujours unique). A premiere vue, l'operation me parait extremement legere (le tuple a ete lu dans son ensemble (n'est-ce pas ?), vu qu'il a ete trouve par la clause Where, et il a ete trouve rapidement grace aux index).

    Je pense qu'il doit me manquer un element de raisonnement, mais je ne vois pas lequel : pour moi il s'agit de l'utilisation classique d'un tuple d'une table (avec ses index) ou l'on verifie simplement un des elements ?

    merci d'avance pour vos eclaircissement a cet esprit embrume par le metro matinal... ^_^;

    ps: je ne sais pas grand chose sur les vues (on les utilise tres peu ici) ... mais ca m'interesse

  10. #10
    Rédacteur
    Avatar de WOLO Laurent
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Mars 2003
    Messages
    2 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Congo-Brazzaville

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 2 741
    Par défaut
    C'est bien connu dans les règles d'écriture des ordres SQL optimisés :
    Il vaut mieux privilégier la logique ensembliste par rapport à la logique procédurale. Plus simplement, Le case serait plus lent que son équivalent sans update.
    Vous voulez maintenant vous rassurez : Lancer le plan d'execution de ces deux requêtes et nous allons vous aidez dans l'analyse de ceux-ci.

    Découvrez la FAQ de MS SQL Server.
    La chance accorde ses faveurs aux esprits avertis !

  11. #11
    Membre éclairé
    Avatar de Mindiell
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    735
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 735
    Par défaut
    Moi je dirais qu'il vaut mieux approfondir ses connaissances de T-SQL

    Voilà une solution avec un seul update et sans case :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    UPDATE tblObjets 
    SET Status = SIGN ( Restant - 1 )
    , Restant = Restant - 1 
    WHERE Perso = @lePerso 
    AND Index = @indexObjet 
    AND Status <> 0
    Et voilà ! La fonction SIGN te retourne 1 en cas de valeur positive et 0 en cas de 0. A priori, le -1 retourné en cas de valeur négative ne sera jamais retourné puisque le Restant minimum est de 0, non ?

    Et hop !

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

Discussions similaires

  1. Mette a jour 2 colonnes dans un UPDATE??
    Par Devil666 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 19/07/2005, 15h02
  2. REPLACE dans un UPDATE
    Par outdial dans le forum Requêtes
    Réponses: 3
    Dernier message: 20/09/2004, 11h00
  3. Une ch'tite bizarrerie dans les Updates de SQL Server
    Par Wakko2k dans le forum MS SQL Server
    Réponses: 12
    Dernier message: 08/04/2004, 14h14
  4. GROUP BY et HAVING dans un UPDATE
    Par MashiMaro dans le forum Langage SQL
    Réponses: 3
    Dernier message: 26/08/2003, 08h03
  5. Réponses: 6
    Dernier message: 26/01/2003, 13h45

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