Partage
  • Partager sur Facebook
  • Partager sur Twitter

principe general des bases de données

Plus d'entrées ou plus de calculs ?

Sujet résolu
    20 décembre 2010 à 5:46:23

    Bonjour à tous.

    Voilà une question qui me revient souvent, alors je la pose aux zéro-pros pour en être debarassé !

    J'explique par un exemple :
    J'ai pour chacun de mes utilisateurs referencés dans une base SQL 2 entrées de nombres entiers que j'appellerai A et B.
    Une page de mon site affiche un classement des utilisateurs par la somme de A et B.
    Dans ce cas, vaut-il mieux faire un affichage par (A + B) ou alors créer une entrée C, somme de A et B, et afficher un classement par C ?

    Vous me suivez ?
    Et dans ce cas, faut-il carrément rajouter une entrée "classement" qui sera la position de chaque utilisateur dans le classement par rapport à C, et recalculer tout ça à chaque changement de A ou B ?

    Merci de vos avis !
    • Partager sur Facebook
    • Partager sur Twitter
      20 décembre 2010 à 10:15:25

      Pour faire un ORDER BY x LIMIT n avoir un index sur x aide grandement (ça évite le tri).

      Sous postgres tu créé un index sur (a+b)
      MySQL ne supporte pas les index d'expression donc tu dois matérialiser a+b dans une colonne bidon C comme tu dis (pour pas te prendre la tête, utilise un trigger).
      • Partager sur Facebook
      • Partager sur Twitter
        20 décembre 2010 à 10:17:03

        bonjour,
        il n'y a jamais de réponse absolue.
        A un niveau conceptuel, on s'interdit "le stockage" les calculs, parce que à ce niveau on fait abstraction du temps et de l'espace.
        Au niveau du SGBDR (Niveau physique), en revanche, l'optimisation technique est primordiale.
        Les benchmarks permettent d'orienter les stratégies.
        Les SGBDR, avec la puissance de SQL, permettent d'exécuter rapidement certaines requêtes. Mais parfois il est préférable de stocker au préalable les résultats des calculs (C'est typique des datawarehouse).
        C'est ton cas particulier, avec des tests préalables, qui te permettra de choisir la meilleure solution.
        Comme je le disais, l'optimisation dépend de l'espace et du temps.
        Donc, 2 critères sont à prendre en compte, la quantité de données traitées et de la fréquence de mises à jour.
        Les réponses sont parfois plus compliquées que les questions :)
        • Partager sur Facebook
        • Partager sur Twitter
          20 décembre 2010 à 19:57:25

          ok.
          donc je ne suis pas débarrassé de cette question ...
          merci à tous les 2 de vos réponses, je vais me pencher sur les benchmarks pour tester ce qui fonctionne le mieux, pour chaque cas.
          • Partager sur Facebook
          • Partager sur Twitter
            24 décembre 2010 à 16:27:54

            Lord, vu tes interventions sur le sujet, tu m'as l'air de bien maîtriser les triggers.
            Peux-tu m'en expliquer succintement le fonctionnement ?
            Je trouve peu d'articles sur le sujet et comme d'hab, la doc de MySQL n'est vraiment pas d'une grande aide.
            Elle traite d'un exemple précis que j'arrive bien à comprendre, mais lorsqu'il s'agit de transférer tout ça à un autre cas concret, ça se complique.

            donc j'aimerai tout simplement qu'une colonne "membre_total" de ma table membres soit égale à la somme des colonnes "membre_score"+"membre_resultat"
            voila ce que j'ai fait :
            CREATE TRIGGER somme AFTER UPDATE ON membres
            FOR EACH ROW
            BEGIN
            SET `membre_total` = `membre_resultat` + `membre_score`
            END
            


            J'ai également essayé de passer par une variable intermediaire du genre :

            SET @total = `membre_resultat` + `membre_score`
            SET `membre_total`=@total
            


            sans succès.
            Can you help me ?
            • Partager sur Facebook
            • Partager sur Twitter
              24 décembre 2010 à 17:05:10

              bonjour,
              SET `membre_total` = `membre_resultat` + `membre_score` ne fait que créer une variable et lui affecter une expression.
              Cela ne modifie pas les valeurs de la table.
              Apparemment tu voudrais faire un UPDATE dans un trigger AFTER UPDATE ce qui conduirait à une boucle infinie.
              Si tu envoyais la structure simplifiée de ta table genre membres_scores(id_membre, membre_score, membre_resultat, membre_total, ...)!
              Et le sens des colonnes et l'objectif et le contexte.
              Parce qu'il me semble qu'un ordre UPDATE devrait suffir dans ton cas, mais je veux être certain de bien comprendre le sens de ta requête.

              • Partager sur Facebook
              • Partager sur Twitter
                24 décembre 2010 à 17:10:40

                euh disons que je veux que "membre_total" soit automatiquement recalculé des lors qu'un update est fait soit sur "membre_score" soit sur "membre_resultat"

                Je dois filer au boulot la, mais j'essaie de m'expliquer plus en detail tout à l'heure.
                merci !
                • Partager sur Facebook
                • Partager sur Twitter
                  24 décembre 2010 à 17:20:34

                  re,
                  code SQL avec des constantes ... dans une application cela est adapté avec des variables.
                  Soit l'une soit l'autre en fonction du contexte.
                  UPDATE membres_scores
                  SET membre_score = 10, membre_total = membre_score + 10
                  WHERE id = 1;
                  ou
                  UPDATE membres_scores
                  SET membre_resultat = 5, membre_total = membre_resultat + 5
                  WHERE id = 1;
                  

                  Enfin il faut que tu vois par rapport à ton contexte si c'est membre_total = membre_total + ... ou membre_total = membre_score + ...
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 décembre 2010 à 20:23:03

                    euh ...
                    j'avoue ne pas trop te suivre la.

                    Pour le contexte : c'est un site WEB et pas une application.
                    Chacun de mes membres peuvent gagner des points de 2 façons : il y a les points par "resultats", et ceux par "scores".
                    une page de mon site affiche le classement global, les points pris en compte sont donc dans ce cas l'addition des points "resultats" et des points "scores", ce que j'appelle "total"

                    pour le moment, j'affiche cette page en faisant un "ORDER BY resultats+scores"
                    mais suite à la discussion precedente, j'aimerai créer une entrée "total" dans la bdd, et ensuite faire le "ORDER BY total"
                    Lord me conseillait d'utiliser un trigger pour regir le comportement de l'entrée "total"
                    Par contre, si je comprend bien, toi tu fonctionnerais plutot sans le trigger ?

                    edit :
                    je ne comprend vraiment rien aux triggers.
                    bon vu qu'on s'eloigne du sujet de départ, je passe ce topic en [résolu] et j'en ouvre un nouveau.
                    merci !
                    • Partager sur Facebook
                    • Partager sur Twitter
                      25 décembre 2010 à 15:36:56

                      Citation : sicilien007

                      code SQL avec des constantes ... dans une application cela est adapté avec des variables.



                      Bien sûr il faut éviter cette "solution" comme la peste puisque ça t'oblige à modifier toutes les requêtes de ton code.

                      Donc, après avoir lu mon petit tuto sur les triggers (clique sur mon pseudo)...

                      - il te faut un trigger BEFORE UPDATE et BEFORE INSERT, pas AFTER
                      - dedans tu mets juste NEW.total = NEW.resultat + NEW.score
                      - ton trigger a modifié les valeurs de l'update avant que celui ci se fasse (BEFORE UPDATE)
                      - l'update continue normalement avec les nouvelles valeurs

                      genre

                      CREATE TRIGGER somme AFTER UPDATE ON membres
                      FOR EACH ROW
                      BEGIN
                      NEW.total = NEW.resultat + NEW.score
                      END
                      


                      bon, je vais cuver...
                      • Partager sur Facebook
                      • Partager sur Twitter
                        25 décembre 2010 à 16:30:12

                        merci Lord
                        mais ...

                        dans le code que tu m'as mis, je dois bien comprendre qu'il faut un BEFORE UPDATE et pas AFTER ? (je pense qu'il y a une coquille?)
                        ne faut-il pas un "SET" avant l'action à effectuer ?

                        si l'on utilise un AFTER, et que l'on travaille sur la ligne "NEW" (entre temps, j'etais tombé sur ton tuto !) on va additionner les anciennes valeurs de resultat et score, avant qu'elles ne soient updatées non ? Ce n'est pas ce qu'il me faut, l'addition doit prendre en compte la nouvelle valeur, soit de resultat, soit de score.

                        j'ai essayé ceci, mais sans succès
                        CREATE TRIGGER somme BEFORE UPDATE ON membres
                        FOR EACH ROW
                        BEGIN
                        SET NEW.membre_total = NEW.membre_resultat + NEW.membre_score
                        END
                        


                        erreur retournée :
                        #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 5
                        • Partager sur Facebook
                        • Partager sur Twitter
                          25 décembre 2010 à 16:41:54

                          > si l'on utilise un AFTER, et que l'on travaille sur la ligne "NEW"

                          Dans un trigger AFTER UPDATE, l'update est déjà fait, donc c'est trop tard pour modifier les valeurs.
                          Il faut glisser la nouvelle valeur du total dans l'UPDATE en cours, pour ça il faut un trigger BEFORE UPDATE.

                          Effectivement il manquait un SET, c'est une spécificité MySQL... tout comme la chierie de "DELIMITER machin"

                          CREATE TABLE popo (a INT, b INT, t INT ) ENGINE=InnoDB;
                          
                          DELIMITER $$
                          
                          CREATE TRIGGER popo_update_t
                          BEFORE UPDATE ON popo
                          FOR EACH ROW
                          BEGIN
                             SET NEW.t = NEW.a + NEW.b;
                          END$$
                          
                          CREATE TRIGGER popo_insert_t
                          BEFORE INSERT ON popo
                          FOR EACH ROW
                          BEGIN
                             SET NEW.t = NEW.a + NEW.b;
                          END$$
                          
                          DELIMITER ;
                          
                          INSERT INTO popo (a,b) VALUES (1,2);
                          
                          SELECT * FROM popo;
                          
                          UPDATE popo SET a=a+1;
                          
                          SELECT * FROM popo;
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            25 décembre 2010 à 17:08:26

                            Citation : Lord Casque Noir

                            > si l'on utilise un AFTER, et que l'on travaille sur la ligne "NEW"

                            Dans un trigger AFTER UPDATE, l'update est déjà fait, donc c'est trop tard pour modifier les valeurs.
                            Il faut glisser la nouvelle valeur du total dans l'UPDATE en cours, pour ça il faut un trigger BEFORE UPDATE.



                            Euh oui, pardon je voulais dire "si l'on utilise un BEFORE ..." comme tu me l'as expliqué au dessus.
                            oulala, on ne va pas s'en sortir !

                            Enfin si, c'est bon j'ai réussi à faire fonctionner mon premier trigger !
                            Champomy pour tous !

                            Il manquait en fait les "DELIMITER" dans le code que j'ai posté au dessus

                            grand merci à toi Lord
                            maintenant que j'en ai un qui fonctionne, je vais pouvoir plus facilement me pencher dessus et en découvrir les possibilités
                            • Partager sur Facebook
                            • Partager sur Twitter
                              7 janvier 2011 à 15:21:45

                              me voici de retour avec un nouveau souci que je n'arrive pas à solutionner ...

                              donc le trigger en requete SQL en local, no soucy.
                              mais lorsque j'ai voulu le faire sur ma base distante : erreur, vous n'avez pas les droits "SUPER" pour faire cette action (en gros)
                              je suis chez o2switch
                              après contact avec le support d'o2switch, il s'avere que l'utilisateur sous lequel je me connecte lorsque j'accede à phpmyAdmin (via cPanel) ne peut etre modifié, et ses droits encore moins.
                              la seule solution d'après eux est de créer le trigger via un script PHP, par lequel je peux user d'un autre utilisateur, qui lui a les droits necessaires.

                              Bref, j'essaie de créer mon trigger via une requete pdo.
                              voila ce que j'ai fait:
                              <?php
                              $insertion = $bdd->exec("
                              CREATE TRIGGER popo_update_t
                              BEFORE UPDATE ON popo
                              FOR EACH ROW
                              BEGIN
                                 SET NEW.t = NEW.a + NEW.b;
                              END
                              ");						
                              if ($insertion)
                              {
                                 $message="Le trigger a bien<br />été pris en compte.";
                              }
                              else
                              {
                                 $message="Une erreur s'est produite.<br />Le trigger n'a<br />pas été pris en compte.";
                              }
                              echo $message;
                              ?>
                              


                              et j'obtiens le mauvais message, bien entendu ...
                              je suis bon, au niveau syntaxe ?
                              • Partager sur Facebook
                              • Partager sur Twitter
                                7 janvier 2011 à 15:48:48

                                rajoute le bidule avec "DELIMITER" dedans, sinon il coupe au premier ;
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  8 janvier 2011 à 10:07:41

                                  comme ça ?
                                  <?php
                                  $insertion = $bdd->exec("
                                  DELIMITER $$
                                  CREATE TRIGGER popo_update_t
                                  BEFORE UPDATE ON popo
                                  FOR EACH ROW
                                  BEGIN
                                     SET NEW.t = NEW.a + NEW.b;
                                  END$$
                                  
                                  ");
                                  ?>
                                  

                                  ça ne fonctionne pas non plus.
                                  Le problème, je suppose, est que ça fait 2 instructions (le DELIMITER + le CREATE) dans une requete exec.
                                  On ne peut en envoyer qu'une je crois.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    8 janvier 2011 à 11:30:35

                                    Quelle erreur ça renvoie ?
                                    Tu utilises PDO ?
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      8 janvier 2011 à 11:36:43

                                      pas d'erreur, enfin par rapport au code posté au dessus, la page m'ecrit :"Une erreur s'est produite.Le trigger n'a pas été pris en compte."
                                      oui j'utilise PDO
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        8 janvier 2011 à 11:59:26

                                        active les exceptions de PDO et ça te donnera un message d'erreur
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          8 janvier 2011 à 12:08:46

                                          ok, j'ai ça:

                                          Citation : pdo

                                          Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER $$ CREATE TRIGGER popo_update_t BEFORE UPDATE ON popo FOR EACH ROW BEG' at line 1' in *********** Stack trace: #0 ***********: PDO->exec('?DELIMITER $$?C...') #1 {main} thrown in *****************

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            8 janvier 2011 à 12:22:45

                                            En fait y'a pas besoin de DELIMITER, ceci fonctionne :

                                            <?
                                            query( "
                                            CREATE TRIGGER popo_update_t
                                            BEFORE UPDATE ON popo
                                            FOR EACH ROW
                                            BEGIN
                                               SET NEW.t = NEW.a + NEW.b;
                                            END;
                                            " );
                                            


                                            Je me demande pourquoi ça ne marchait pas au début...
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              8 janvier 2011 à 12:32:49

                                              euh ... fallait que j'utilise query, et pas exec ?

                                              merci, effectivement ça fonctionne.
                                              et j'obtiens ce message :

                                              Citation : pdo

                                              Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1227 Access denied; you need the SUPER privilege for this operation' in *************** Stack trace: #0 *********************: PDO->query('?CREATE TRIGGER...') #1 {main} thrown in *****************


                                              Je n'ai toujours pas les droits pour créer le trigger ....
                                              Ils se sont foutus de moi chez o2switch :colere:
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                11 janvier 2011 à 16:42:27

                                                après avoir bien bataillé en mails et tchat avec o2switch, je viens de réussir à placer mon trigger sur ma base distante !

                                                :D
                                                • Partager sur Facebook
                                                • Partager sur Twitter

                                                principe general des bases de données

                                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                • Editeur
                                                • Markdown