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 :

Utiliser LEFT JOIN sur une grosse base de données


Sujet :

Requêtes MySQL

  1. #1
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut Utiliser LEFT JOIN sur une grosse base de données
    Bonjour,
    j'utilisais jusqu'à présent une requête assez massive utilisant 8 "left join".
    Nous avons récemment importe des données, les tables contiennent désormais un nombre important d'enregistrements. (50000 produits environs)
    Et ma requête prends environ 15 secondes a l’exécution, trop long pour un site web...
    Lors d'un autre projet, j'avais pu diviser une telle requête en plusieurs requêtes différentes mais je ne peux pas faire la même chose ici, étant donne que je dois appliquer plusieurs filtres de recherche...

    Voici ma requête, je pense qu'elle est assez explicite
    Merci d'avance pour votre aide si vous voyez une quelconque optimisation ou quelque chose qui ne devrait pas être là.

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `product_retailers` pr 
        ON (p.`id` = pr.`product_id`) 
      LEFT JOIN `retailers` r 
        ON (r.`id` = pr.`retailer_id`) 
      LEFT JOIN `user_products` up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
      LEFT JOIN `experiences` e 
        ON (e.`id` = ei.`experience_id`) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20
    Bractar the French fry eater
    http://www.flale.com

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    bonjour,

    a quoi sert le distinct ?

    Avez-vous indexé les colonnes de jointure ?

    les jointures avec les tables r, pr, up, ei, e ne servent à rien car vous ne faites aucune sélection dessus

  3. #3
    Membre régulier Avatar de Sakukun
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2011
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 74
    Points : 113
    Points
    113
    Par défaut
    Bonjour,
    il ce sert de up et ei pour filtrer de ces tables en fonction de "UserProduct" et récupérer la date , a part r, e et pr, qui sauf erreur servent a rien ici ou alors il manque d'autres filtres.

    Pour les index il à l'air de se servir que des id donc les clé primaire si c'est bien crée, donc pas de souci a ce niveau là à priori...

    Après exécute ta requête avec un EXPLAIN devant, si tu as fait beaucoup de modification dans tes indexs tu peux les rebuild.

    Après a part tourner sur un Pentium 4 ya pas de raison qu'avec 50k de lignes tu mette 15 sec pour une telle requête !

    Cordialement,
    Si un commentaire t'as aidé pense à mettre un .

  4. #4
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par Sakukun Voir le message
    Pour les index il à l'air de se servir que des id donc les clé primaire si c'est bien crée, donc pas de souci a ce niveau là à priori...
    ,

    Désolé de ne pas pratiquer l'art de la divination

  5. #5
    Membre régulier Avatar de Sakukun
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2011
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 74
    Points : 113
    Points
    113
    Par défaut


    J'ai dit "à priori" j'en sais pas plus que toi hélas , mais ca parrait logique que ce soit le cas
    Si un commentaire t'as aidé pense à mettre un .

  6. #6
    Membre éclairé
    Avatar de yimson
    Homme Profil pro
    Consultant Big Data
    Inscrit en
    Janvier 2009
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant Big Data
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 215
    Points : 747
    Points
    747
    Par défaut
    Bonjour Bractar,

    Je suis à priori d'avis avec punkoff et Sakukun.

    Mais tu pourrais essayer de faire un count sur l'ensemble des résultats avec ta requête et un autre count avec la requête proposée par punkoff sans les dernières jointures sur les tables r, pr, up, ei, e et comparer les résultats des deux counts.

    On pourra comprendre mieux la citation suivante
    Envoyé par punkoff
    les jointures avec les tables r, pr, up, ei, e ne servent à rien car vous ne faites aucune sélection dessus

  7. #7
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    que donne ceci :
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `product_retailers` pr 
        ON (p.`id` = pr.`product_id`) 
      LEFT JOIN `retailers` r 
        ON (r.`id` = pr.`retailer_id`) 
      LEFT JOIN (
            SELECT `product_id`, `created_at` as `tagged_date`
            FROM `user_products`
            ORDER BY  `tagged_date`
            LIMIT 0,20 ) up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
      LEFT JOIN `experiences` e 
        ON (e.`id` = ei.`experience_id`) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20

  8. #8
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Bonjour,
    merci pour votre aide.

    à quoi sert le distinct ?
    -> un produit ne doit apparaître qu'une seule fois dans le résultat

    les jointures avec les tables r, pr, up, ei, e ne servent à rien car vous ne faites aucune sélection dessus
    -> r et pr: en effet, ils ne servaient a rien dans ce cas. Je les utilisaient lorsque le filtre `retailer` était activé.
    -> up et ei vont ensemble, comme le disait Sakukun, ces tables sont utilisées pour récupérer la date
    -> e: en effet, inutile dans ce cas, dépends d'un filtre qui n'est pas active par défaut

    Le temps de réponse est a peu près le même après avoir fait ces changements.

    La requête obtenue étant:

    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
    30
    31
    32
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `user_products` up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20
    Et voici un explain (avec une table de produits d'environ 3000 lignes, environ 4 secondes afin d'obtenir les résultats)



    aieeeuuuuu: plusieurs erreurs dans cette requête (la principale étant: Unknown column 'up.id' in 'on clause')
    Bractar the French fry eater
    http://www.flale.com

  9. #9
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par bractar Voir le message
    aieeeuuuuu: plusieurs erreurs dans cette requête (la principale étant: Unknown column 'up.id' in 'on clause')
    Avez vous essayé de les corriger ? le principe est de mettre le LIMIT 20 dans une sous requete pour limiter le volume de données traité par MySQL. En effet, la colonne id de la table que j'ai mise en sous requete est utilisée, il faut donc l'ajouter dans la sous requete.
    Il faudra par ailleurs peut etre revoir le LIMIT, mais je ne connais pas vos cardinalités. Donc la requete est à corriger, puis à adapter si possible. pour la colonne manquante :

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
     
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `product_retailers` pr 
        ON (p.`id` = pr.`product_id`) 
      LEFT JOIN `retailers` r 
        ON (r.`id` = pr.`retailer_id`) 
      LEFT JOIN (
            SELECT `id`,`product_id`, `created_at` AS `tagged_date`
            FROM `user_products`
            ORDER BY  `tagged_date`
            LIMIT 0,20 ) up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
      LEFT JOIN `experiences` e 
        ON (e.`id` = ei.`experience_id`) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20

    Enfin, je pense que vous pouvez certainement remplacer plusieurs jointures externes par des jointures internes, mais là encore, sans connaitre votre modèle, difficile d'en dire plus.

  10. #10
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par bractar Voir le message
    Bonjour,
    merci pour votre aide.

    à quoi sert le distinct ?
    -> un produit ne doit apparaître qu'une seule fois dans le résultat
    On ne met un distinct que dans le cas où l'on est une requete qui ramene des doublons.
    Est-ce le cas ici ?

    Vu que vous sélectionnez une 10ene de colonnes de tables différentes j'ai un doute.

    Et si c'est le cas c'est que vous avez surement une jointure non utilisée dans la clause de sélection qui fait apparaitre des doublons


    L4approche de aieeeuuuuu est bonne, il faudrait voir si rajouter un index sur la colonne date change le plan ou non.

  11. #11
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    ok merci,

    aieeeuuuuu: je vais tester la requête

    punkoff: oui, j'ai des doublons sans utiliser le distinct

    je vous tiens ou courant...
    Bractar the French fry eater
    http://www.flale.com

  12. #12
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Bonjour,

    j'ai crée un schéma "simplifie" pour l'occasion, j’espère que ça aidera


    J'ai essayé la requête, malheureusement, elle ne fonctionne pas comme désirée.
    Je comprends la démarche qui limite a 20 le volume de données traité par MySQL mais il me semble que pour que cela fonctionne, nous devrions avoir un genre de "symétrie" entre les tables "products" et "user_products", ce qui n'est pas le cas.

    Pour expliquer un peu mon programme, des produits peuvent être "taggés" sur des images (expériences). Donc un même produit peut être réutilisé plusieurs fois (sur différentes expériences).
    Bractar the French fry eater
    http://www.flale.com

  13. #13
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    En effet, avec les left join , ça ne sera pas très efficace. Mais d'ailleurs, pourquoi autant de LEFT JOIN.

    Essayez plutôt comme ceci, mais il y a surement encore d'autres choses a régler dans cette requête :

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
     
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
    	(
            SELECT `id`,`product_id`, `created_at` AS `tagged_date`
            FROM `user_products`
            ORDER BY  `tagged_date`
            LIMIT 0,20 
       ) up
      INNER JOIN   `products` p 
    	ON (up.`product_id` = p.`id`) 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `product_retailers` pr 
        ON (p.`id` = pr.`product_id`) 
      LEFT JOIN `retailers` r 
        ON (r.`id` = pr.`retailer_id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
      LEFT JOIN `experiences` e 
        ON (e.`id` = ei.`experience_id`) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20
    Indiquez aussi si le temps traitement est déjà meilleur.

  14. #14
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Bonjour,

    j'ai essaye votre requête mais comme dit précédemment, nous ne pouvons pas limiter la table user_products, c'est la table products qui doit impérativement être limitée

    J'ai essaye ceci qui s’exécute très rapidement (< 1s) mais qui malheureusement renvoie des doublons (inner join a la place de left join sur user_products)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT DISTINCT 
      p.`id` AS `product_id`,
    [...]
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      INNER JOIN `user_products` up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
    [...]
    Dans la table products se trouvent tous mes produits, dans la table user_products, les produits taggés (utilisés). Donc un même produits peut apparaître plusieurs fois dans user_products.

    "Mais d'ailleurs, pourquoi autant de LEFT JOIN"
    Que suggéreriez-vous? Des sous-requêtes dans la requête principale? Dans l'extraction des résultats? (results.each(:as => :hash) do |row|... SOUS REQUETE ... end)

    Merci encore de votre précieuse aide
    Bractar the French fry eater
    http://www.flale.com

  15. #15
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Voici ce que j'ai fait afin d’éliminer les (faux) doublons, je pense que c'est assez bon...

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`max_created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
      `products` p 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      INNER JOIN 
        (SELECT 
          `id`,
          `product_id`,
          MAX(`created_at`) `max_created_at`
        FROM
          `user_products` 
        GROUP BY `product_id`) up 
        ON (up.`product_id` = p.`id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
    ORDER BY `tagged_date` DESC, `product_name` 
    LIMIT 0, 20
    J'ai un autre problème de vitesse d’exécution sur une dérivée de cette même requête, je vous tiens au courant...
    Bractar the French fry eater
    http://www.flale.com

  16. #16
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Il y a quand même quelque chose que je ne comprend pas...
    Vous triez sur tagged_date, colonne appartenant à user_product, puis vous ne gardez que les 20 premiers résultats.

    Je pourrais comprendre que vous obteniez au final moins de 20 lignes, (si certaines sont éliminées lors des jointures), mais je ne vois pas en quoi faire une jointure interne provoque des doublons... pourriez vous donner un exemple de ces doublons ? quelque chose m'échappe.

    Notez par aileurs que j'ai omis le tri décroissant (DESC) dans la sous requête. ajoutez le.


    Pour ce qui est des jointures externes : par exemple, comme vous avez une contrainte d'intégrité entre product_brands et brands, vous pouvez mettre une jointure interne entre ces deux tables, plutôt qu'une jointure externe.

  17. #17
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Bonjour,
    dans la table products, j'ai tous les produits disponibles sans doublon.
    dans la table user_products, j'ai tous les produits utilisés par les utilisateurs, un même id produits peut donc y revenir plusieurs fois. Mais ce dont j'ai besoin, c'est la liste des produits utilisés par les utilisateurs sans répéter le même produit.



    Maintenant, la solution qui semble fonctionner:



    Je ne suis pas vraiment expert en sql, si vous voyez quelque chose de mieux, je suis toujours preneur.

    Merci
    Bractar the French fry eater
    http://www.flale.com

  18. #18
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    hmmm, alors vous deviez avoir des doublons dans votre requete initiale aussi non ?

    vous pouvez aussi essayer ceci :

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
     
     
    SELECT DISTINCT 
      p.`id` AS `product_id`,
      p.`name` AS `product_name`,
      p.`uuid`,
      up.`created_at` AS `tagged_date`,
      p.`price`,
      p.`url`,
      p.`category_id`,
      c.`name` AS `category_name`,
      b.`name` AS `brand_name`,
      pimg.`id` AS `product_image_id`,
      pimg.`image`,
      pimg.`original_image_path` 
    FROM
    	(
            SELECT `id`,`product_id`, `created_at` AS `tagged_date`
            FROM `user_products` a
            WHERE NOT EXISTS( 
                    SELECT 1
                    FROM `user_products` b
                    WHERE b.product_id = a.product_id
                    AND b.created_at > a.created_at
            )
            ORDER BY  `tagged_date` DESC
            LIMIT 0,20 
       ) up
      INNER JOIN   `products` p 
    	ON (up.`product_id` = p.`id`) 
      LEFT JOIN `product_brands` pb 
        ON (p.`id` = pb.`product_id`) 
      LEFT JOIN `brands` b 
        ON (b.`id` = pb.`brand_id`) 
      LEFT JOIN `product_images` pimg 
        ON (pimg.`product_id` = p.`id`) 
      LEFT JOIN `categories` c 
        ON (c.`id` = p.`category_id`) 
      LEFT JOIN `product_retailers` pr 
        ON (p.`id` = pr.`product_id`) 
      LEFT JOIN `retailers` r 
        ON (r.`id` = pr.`retailer_id`) 
      LEFT JOIN `experience_items` ei 
        ON (
          ei.`item_id` = up.`id` 
          AND ei.`item_type` = 'UserProduct'
        ) 
      LEFT JOIN `experiences` e 
        ON (e.`id` = ei.`experience_id`) 
    ORDER BY `tagged_date` DESC 
    LIMIT 0, 20
    Bien sûr, placez un index sur : user_products(created_at, product_id)

  19. #19
    Membre confirmé
    Avatar de tse_jc
    Homme Profil pro
    Data Solutions
    Inscrit en
    Août 2010
    Messages
    287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Data Solutions
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2010
    Messages : 287
    Points : 597
    Points
    597
    Billets dans le blog
    4
    Par défaut
    bonjour,

    o_O encore un MCD modélisé à l'arrache, après c'est la faute aux jointures...

    Alors on va se limiter juste au cas des produits et des utilisateurs pour une petite démonstration
    1) dans la table products, j'ai tous les produits disponibles sans doublon.
    2) Dans la table products se trouvent tous mes produits, dans la table user_products, les produits taggés (utilisés). Donc un même produits peut apparaître plusieurs fois dans user_products.
    Votre affirmation 1) est déjà fausse car dans la table produits, pour un produit donné, le fait d'avoir crée une DF avec l'id utilisateur (cardinalité 1-1), si un produit x (non utilisé d'après votre règle de gestion) est associé à y utilisateurs il existera y fois dans la table products et si il est également utilisé par ces mêmes y utilisateurs il apparaîtra également y fois dans la table user_products.... ce qui est impressionnant de voir la volumétrie inutile qui est générée par ce modèle qui est de l'ordre du carré... personnellement je n'ai jamais vu cela, mais je ne pourrais plus le dire^^

    Donc le fait que deux produits identiques peuvent exister avec une id technique différente, pour faire une requête dans laquelle vous souhaitez obtenir
    la liste des produits utilisés par les utilisateurs sans répéter le même produit.
    cela vous oblige à requêter basiquement la table user_products et à faire un regroupement de produit par libellé de produit, donc pour le moins et au mieux un full scan de votre table user_products.

    Je vous donne la structure de filtrage nécessaire pour l'unicité produit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SELECT t1.product_id, t2.name 
    FROM user_products AS t1
    INNER JOIN products AS t2 on t1.product_id=t2.id
    GROUP BY t1.product_id, t2.name
    HAVING count(lower(t2.name))=1
    ORDER BY t2.name;
    Bon courage car j'espère pour vous dans votre malheur que deux produits identiques on un libellé strictement identique (pas d'erreur de saisie), sinon vous n'aurez aucun moyen d'éviter les doublons produits utilisés.
    ++

  20. #20
    Membre du Club Avatar de bractar
    Inscrit en
    Janvier 2004
    Messages
    224
    Détails du profil
    Informations forums :
    Inscription : Janvier 2004
    Messages : 224
    Points : 63
    Points
    63
    Par défaut
    Je viens de vérifier user_id dans la table products. En effet, cela porte a confusion. C'est l'id de l'utilisateur qui a crée le produit pour la première fois. Donc, je confirme, pas de doublons dans cette table.

    Je ne vous ai montré que la partie de la base de données ou je travaille actuellement, beaucoup d'autre choses sont aberrantes. Malheureusement 3 développeurs qui s'en foutaient un peu sont passés avant moi.

    Les requêtes gérées par Ruby on Rails prenaient environ 30 secondes! Avec des requêtes directes, j'ai pu passer a 15 secondes lorsque j'ai ouvert ce ticket. Et environ 1 seconde actuellement. Cependant, j'ai encore quelques petits soucis avec les résultats... je cherche toujours En tout cas j'apprécie vraiment toute l'aide fournie jusqu’à présent!
    Bractar the French fry eater
    http://www.flale.com

Discussions similaires

  1. LEFT JOIN sur une même table
    Par grinder59 dans le forum Requêtes
    Réponses: 2
    Dernier message: 13/01/2012, 15h30
  2. utilisation LEFt JOIN ds une trigger DELETE
    Par moukit233 dans le forum Requêtes
    Réponses: 1
    Dernier message: 15/04/2010, 18h48
  3. Réponses: 4
    Dernier message: 06/11/2009, 12h35
  4. 2 LEFT JOIN sur une même table
    Par dakan dans le forum Langage SQL
    Réponses: 2
    Dernier message: 02/10/2007, 13h51
  5. [MySQL] Backup d'une grosse base de données (60MB)
    Par MiJack dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 01/11/2005, 18h22

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