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 MySQL Discussion :

Optimiser des requêtes avec exclusions


Sujet :

Requêtes MySQL

  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2018
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Optimiser des requêtes avec exclusions
    Bonjour,

    Je possède une base de données qui liste les fruits par "type" et par "couleur".

    Je souhaite créer des paniers en allant chercher 10 fruits selon des types et des couleurs définis par un script aléatoire.
    Mon problème vient du fait que j'ai besoin que la sélection des 10 fruits soit toujours différente (aucun fruit en double dans mon panier).
    Il est possible que certains paniers soient composés uniquement de fruits du même type ou de la même couleur, ce n'est pas grave.

    Voici comment je m'y prends actuellement :

    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $req = $database->prepare('SELECT id FROM fruits WHERE type = ? AND couleur = ? ORDER BY RAND() LIMIT 1');
    $req->execute(array($type_fruit_1, $couleur_fruit_1));
    $fruit_1 = $req->fetch();
    $req->closeCursor();
    *
    $req = $database->prepare('SELECT id FROM fruits WHERE type = ? AND couleur = ? AND id != ? ORDER BY RAND() LIMIT 1');
    $req->execute(array($type_fruit_2, $couleur_fruit_2, $fruit_1['id']));
    $fruit_2 = $req->fetch();
    $req->closeCursor();
    *
    $req = $database->prepare('SELECT id FROM fruits WHERE type = ? AND couleur = ? AND id != ? AND id != ? ORDER BY RAND() LIMIT 1');
    $req->execute(array($type_fruit_3, $couleur_fruit_3, $fruit_1['id'], $fruit_2['id']));
    $fruit_3 = $req->fetch();
    $req->closeCursor();
    *
    ...

    Je trouve cette méthode plutôt "lourde" étant donné qu'elle se poursuit 7 fois encore.
    Savez-vous comment je pourrais optimiser cette partie de mon script ?

    Je vous remercie d'avance pour votre aide.

  2. #2
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 393
    Points
    9 393
    Par défaut
    J'essaierais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM fruits where type = ? and couleur = ? ORDER BY RAND() LIMIT 10
    Ainsi, en une seule requête tu récupères 10 lignes aléatoires.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  3. #3
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2018
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Merci pour ta réponse.

    Ta solution sort bien 10 lignes aléatoires.
    En revanche elle ne me permet pas de répondre à deux grandes difficultés :
    - chaque ligne doit avoir un type déterminé bien spécifique
    - l'ordre des 10 lignes compte

    Par exemple, mon script va me dire de sortir les 10 lignes suivantes :
    - type A
    - type A
    - type A
    - type D
    - type C
    - type D
    - type A
    - type E
    - type B
    - type C

    Une autre fois, il me demandera :
    - type C
    - type C
    - type A
    - type A
    - type A
    - type B
    - type D
    - type F
    - type G
    - type E

    Je n'arrive pas à condenser le tout pour que :
    - chaque ligne appelle un type dans l'ordre
    - chaque type appelle un fruit aléatoire parmi la liste
    - chaque fruit appelé soit unique et ne réapparaisse deux fois au sein d'un même type

    Je ne sais pas si je suis suffisamment clair... merci beaucoup pour l'aide en tout cas.

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Bonjour,

    Essaye cette requête en remplaçant les ? par la liste aléatoire des types et des couleurs que tu souhaites :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT DISTINCT id
    FROM fruits
    WHERE type IN (?)
    	AND couleur IN (?)
    ORDER BY type, couleur
    LIMIT 10
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2018
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Merci pour ton aide.

    Malheureusement cette requête va d'abord me chercher X fruits dans la première couleur, puis X fruits suivant dans la seconde couleur, etc.. jusqu'à 10.

    Je ne veux vraiment pas embêter le forum avec cette requête, il n'y a peut être pas de solution "optimisée" pour mon problème :
    - aller chercher aléatoirement une liste de 10 fruits distincts, dont chacun possède une couleur définie dans un ordre donné non aléatoire, sans que cela ne m'affiche de doublon de fruit ou de fruits qui ne seraient pas de la couleur demandée. :/

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Alors j'ai du mal à comprendre votre besoin.

    Pourriez-vous donner un exemple concret de données présentes et de résultats attendus ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2018
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Aucun problème, c'est que je n'ai pas été assez clair. Merci encore pour le temps accordé.

    Je vais essayer d'être plus clair et de simplifier mon problème avec 1 seule variable discriminante : la couleur


    J'ai une liste de plus de 300 Fruits dans une BDD ayant chacun un id :
    - Pastèque
    - Melon
    - Avocat
    - Pomme
    - Poire
    - Prune
    - Pêche
    - Raisin
    - etc...

    Ces 300 fruits sont classés selon leur couleur :
    - Vert
    - Jaune
    - Rouge
    - Brun
    - Marron
    - Rose
    - etc... (il y a en tout 65 couleur différentes)

    J'ai codé un script qui permet de créer des "paniers alimentaires" combinant des couleurs de fruits dans un ordre donné.
    Par exemple, le panier n°1 sera :
    - Vert
    - Vert
    - Brun
    - Jaune
    - Rouge
    - etc... jusqu'à 10 fruits

    Le panier n°2 sera complètement différent et combinera 10 autres couleurs.
    Idem pour le panier n°3, etc...

    Mon but est simplement de dire à ma BDD :
    - Dans un panier donné, pour chaque couleur de fruit donnée, dans le bon ordre, va me chercher un fruit correspondant au hasard parmi tous ceux possibles
    - Il ne doit jamais y avoir 2 fruits identiques dans la liste des 10 fruits finaux
    - Je précise qu'un ID fruit ne se retrouve que dans une seule couleur

    Ma méthode initiale a été de faire 10 requêtes distinctes où chaque requête suivante exclut l'ID des requêtes précédentes.
    Je me demande s'il existe un moyen plus simple de tout combiner en une seule fois.

  8. #8
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 393
    Points
    9 393
    Par défaut
    Personnellement, je reste du r mon idée initiale, et je l'adapterais ainsi :
    - dans mon panier , je veux par exemple 4 fruits de couleur rouge, 5 de couleur jaune, et 1 de couleur verte.
    Je lancerais donc ces 3 requetes :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT * FROM fruits where type = ? and couleur = 'rouge' ORDER BY RAND() LIMIT 4
    SELECT * FROM fruits where type = ? and couleur = 'jaune' ORDER BY RAND() LIMIT 5
    SELECT * FROM fruits where type = ? and couleur = 'verte' ORDER BY RAND() LIMIT 1
    ou encore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT * FROM fruits where couleur = 'rouge' ORDER BY RAND() LIMIT 4
    union
    SELECT * FROM fruits where couleur = 'jaune' ORDER BY RAND() LIMIT 5
    union
    SELECT * FROM fruits where couleur = 'verte' ORDER BY RAND() LIMIT 1
    Puis je réordonnerais les éléments dans le script PHP.

    On doit aussi pouvoir tenter cela :
    Par exemple, je veux que les fruits rouges soient en position 1,3,6 et 7, les jaunes en 2,4,5,9 et 10, et le vert en 8
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT  decode ( rownum, 1,1,  2,3,  3,6,  4,7)           as rang_total,  id_fruit  FROM fruits where couleur = 'rouge' ORDER BY RAND() LIMIT 4
    union
    SELECT  decode ( rownum, 1,2,  2,4,  3,5,  4,9,  5,10) as rang_total,  id_fruit  FROM fruits where couleur = 'jaune' ORDER BY RAND() LIMIT 5
    uinon
    SELECT  decode ( rownum, 1,8)                                 as rang_total,  id_fruit  FROM fruits where couleur = 'verte' ORDER BY RAND() LIMIT 1
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  9. #9
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 133
    Points : 38 555
    Points
    38 555
    Billets dans le blog
    9
    Par défaut
    Pourquoi mettre un ORDER BY si c'est pour utiliser un RAND() autant supprimer le tri

  10. #10
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    - Dans un panier donné, pour chaque couleur de fruit donnée, dans le bon ordre, va me chercher un fruit correspondant au hasard parmi tous ceux possibles
    - Il ne doit jamais y avoir 2 fruits identiques dans la liste des 10 fruits finaux
    À la limite, le bon ordre, vous pouvez le gérer à l'affichage, ce qui ne sera pas plus mal parce que classer par une requête l'ordre des couleurs n'a pas beaucoup de sens, je trouve...

    En fait, la difficulté vient du fait que vous souhaitez, par exemple, 2 fruits verts, 1 fruit jaune, 4 rouges, 3 bruns. Alors comme une BDD relationnelle est ensembliste, il faut constituer les différents groupes de fruits séparément et les unir.

    Un truc de ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    SELECT DISTINCT id, couleur
    FROM fruits
    WHERE couleur = 'vert'
    ORDER BY RAND()
    LIMIT 2
     
    UNION
     
    SELECT DISTINCT id, couleur
    FROM fruits
    WHERE couleur = 'jaune'
    ORDER BY RAND()
    LIMIT 1
     
    UNION
     
    SELECT DISTINCT id, couleur
    FROM fruits
    WHERE couleur = 'rouge'
    ORDER BY RAND()
    LIMIT 4
     
    UNION
     
    SELECT DISTINCT id, couleur
    FROM fruits
    WHERE couleur = 'brun'
    ORDER BY RAND()
    LIMIT 3
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  11. #11
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 393
    Points
    9 393
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    Pourquoi mettre un ORDER BY si c'est pour utiliser un RAND() autant supprimer le tri
    Si on ne met pas ce order by rand(), on aura les même résultats à chaque exécution. Or, dans le premier message, on parlait de script ''aléatoire''.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  12. #12
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 133
    Points : 38 555
    Points
    38 555
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par tbc92 Voir le message
    Si on ne met pas ce order by rand(), on aura les même résultats à chaque exécution. Or, dans le premier message, on parlait de script ''aléatoire''.
    Rien n'est moins sur : seul ORDER BYgarantit un ordre stable et ce d'autant plus qu'un select * ne permet pas l'usage d'un index couvrant (sauf si, cas très particulier, il existe un index couvrant toutes les colonnes de la table !)
    En l'absence d'ORDER BY, il est fort possible que deux exécutions consécutives de la même requête donne le même résultat, mais selon un ordre différent

  13. #13
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2018
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2018
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Merci beaucoup pour tous ces éclaircissements. Je mets le sujet en résolu !

    Je vais en effet partir sur un groupement des données par couleur que je replacerai ensuite dans le bon ordre une fois la requête effectuée.
    En tout franchise, je n'ai aucune idée comment faire ça, je chercherai :
    - compter le nombre de récurrences dans un tableau en PHP
    - créer des requêtes adaptées où le "LIMIT" s'adapte automatiquement
    - replacer les éléments dans le bon ordre depuis le résultat obtenu ?

    Je vous offre à tous un verre bien volontiers si jamais on doit se croiser.
    Merci encore pour le temps passé sur ce sujet !

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

Discussions similaires

  1. [2005] Optimisation requête avec exclusions
    Par Mizar31 dans le forum Développement
    Réponses: 21
    Dernier message: 24/02/2015, 09h55
  2. Réponses: 0
    Dernier message: 11/06/2014, 09h50
  3. [MySQL] Optimiser une requête avec des tableaux PHP ?
    Par Khleo dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 14/11/2011, 15h49
  4. Optimisation de requête avec Tkprof
    Par stingrayjo dans le forum Oracle
    Réponses: 3
    Dernier message: 04/07/2005, 09h50
  5. optimisation des requêtes
    Par yech dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 21/09/2004, 19h03

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