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 jointure + tri sur colonnes différentes


Sujet :

Requêtes MySQL

  1. #1
    Membre habitué
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Points : 130
    Points
    130
    Par défaut Optimiser jointure + tri sur colonnes différentes
    Bonjour,

    J'ai une requête sur deux tables (en fait plus que ça mais je vais simplifier) qui fait la chose suivante : on a une table d'historique de mouvements (entrées, sorties, etc.) et une table de produits. On veut chercher dans l'historique les produits selon un certain critère (critère se trouvant dans la fiche produit) mais trier le résultat par date (date de l'historique, en fait on utilise l'id de la table) puis renvoyer les 1000 premiers résultats (on ne veut pas remonter trop de lignes à l'appli). On a donc quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT
        *
    FROM
        historique H
        LEFT OUTER JOIN produit P USING (reference)
    WHERE
        P.famille = famille_choisie
        AND H.date between date_debut AND date_fin
    ORDER BY
        H.id DESC
    LIMIT
        1000
    En faisant un EXPLAIN, MySQL me dit "Using Filesort" et la requête est vraiment extrêmement longue. J'ai un index sur la famille, la référence et l'id. Que puis-je faire ?

  2. #2
    Expert éminent
    Avatar de qi130
    Homme Profil pro
    Expert Processus IT
    Inscrit en
    Mars 2003
    Messages
    3 924
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France

    Informations professionnelles :
    Activité : Expert Processus IT
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 3 924
    Points : 6 038
    Points
    6 038
    Par défaut
    Indexer la date.

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    507
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mai 2006
    Messages : 507
    Points : 705
    Points
    705
    Par défaut
    Bonjour,

    Citation Envoyé par qi130 Voir le message
    Indexer la date.
    Effectivement, le traitement sur des types non entiers est toujours plus long...

    De plus il est préférable de faire une jointure sur "reference" si ce dernier est aussi un entier (éviter ici les chaines de caractères).
    Après j'ai moi aussi remarqué que MySql devient un peu lent dès qu'on s'amuse avec les jointures sur des tables de plusieurs (dizaines de) milliers d'éléments.
    Donc si c'est ton cas et que tes références de tes produits que tu veux ne sont pas trop nombreuses tu as interêt à faire ta requête en deux étapes :
    1. 1 tu récupères tes références de produits
    2. 2 tu récupères ton historique


    Autre point, il serait conseillé de ne pas faire des SELECT * mais spécifier les champs que tu souhaites... Cependant je n'ai jamais réellement testé pour voir s'il y a une différence notable.

  4. #4
    Membre habitué
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Points : 130
    Points
    130
    Par défaut
    Ma date est (évidemment) indexée.

    Entier ou chaîne pour la jointure (référence), les performances ne changent pas pour cette requête j'ai tenté les deux comme la référence était initialement une chaîne.

    J'ai également tenté de faire le tout en deux étapes, avec une requête interne, comme avec une table temporaire. J'ai même essayé de poser des index sur la table temporaires. Rien n'y fait.

    Pour info, la table historique compte plusieurs millions de lignes.

    Au final, j'ai ajouté un champ "famille" dans l'historique, et posé un index sur famille+date, c'est très efficace mais je trouve la solution un peu dégueulasse...

  5. #5
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    FROM
        historique H
        LEFT OUTER JOIN produit P USING (reference)
    Ne vaudrait-il mieux pas faire l'inverse ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FROM produit P 
        LEFT OUTER JOIN historique H USING (reference)
    Voir même une jointure interne puisque en principe tous les produits figurant dans l'historique sont dans la table produit non ?

  6. #6
    Membre habitué
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Points : 130
    Points
    130
    Par défaut
    Non, on prévoit le cas où un produit est supprimé de leur référentiel.

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    507
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mai 2006
    Messages : 507
    Points : 705
    Points
    705
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Au final, j'ai ajouté un champ "famille" dans l'historique, et posé un index sur famille+date, c'est très efficace mais je trouve la solution un peu dégueulasse...
    C'est un point de vue.
    Les "optimisations" SQL classiques théoriques t'optimisent la taille de tes bases de données sur le disque, mais pas forcément le temps d'exécutions des requêtes.
    Aujourd'hui les tailles des bases de données sur disque ne sont généralement pas un problème (les disques de plusieurs tera ne sont pas très chers), par contre les vitesses d'accès sont primordiales et les processeurs et la mémoire vive sont chères sans gain évident.

    Alors si tu optimises tes tables pour un accès plus rapide tout en perdant sur leurs tailles, je ne trouve pas que ce soit dégueulasse...

    Après c'est mon point de vue, purement personnel...

  8. #8
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Je viens de relire ton premier message et je me rends compte qu'en fait, ta jointure externe devient une jointure interne puisque tu as une condition dans le WHERE qui porte sur la table externe (P.famille = famille_choisie) comme je l'explique dans mon blog.

    Peut-être que si tu rapatrie la condition de restriction dans la jointure, cela va réduire le temps puisqu'il y aura moins de lignes à joindre ?

  9. #9
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 453
    Points : 18 388
    Points
    18 388
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Non, on prévoit le cas où un produit est supprimé de leur référentiel.
    Il vaut mieux gérer ces cas de figure avec une suppression logique (un flag inactif et une date associée par exemple).

Discussions similaires

  1. [Débutant] Oracle et tri sur colonnes
    Par TheReturnOfMuton dans le forum ASP.NET
    Réponses: 0
    Dernier message: 27/08/2012, 09h25
  2. [XL-2007] Optimisation de tri sur tableau
    Par FanTasTik dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 17/08/2012, 14h43
  3. Regroupement et tri sur champ différents
    Par Dertron dans le forum Requêtes et SQL.
    Réponses: 5
    Dernier message: 22/10/2008, 17h56
  4. [SQL] pagination et tri sur colonne
    Par digger dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 08/05/2007, 22h03
  5. Tri sur colonne DBgrid lié à une TTable
    Par Oluha dans le forum Bases de données
    Réponses: 2
    Dernier message: 02/02/2006, 13h42

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