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

Langage SQL Discussion :

Optimisation de requête


Sujet :

Langage SQL

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    61
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 61
    Points : 33
    Points
    33
    Par défaut Optimisation de requête
    Bonjour,

    ça fait maintenant un bon bout de temps que j'essaie d'optimiser une requête mais je dois avouer que je bloque.

    Ma base est composée (en simplifiant) de 2 tables pour un poids d'environ 1GO (indexes soulignés):
    Item(IDItem, Name);
    ItemCategory(IDItem, IDCategory);

    Chaque "Item" peut avoir plusieurs "Category".

    Je cherche à retrouver les Items appartenant à un ensemble de catégories. Ma démarche consiste donc à trouver dans un premier temps, les IDItem dans ItemCategory :
    J'ai essayé par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT *
    FROM ItemCategory
    GROUP BY IDItem
    HAVING IDCategory='Category1'
    AND IDCategory='Category2'
    Ce qui ne marche pas (sauf quand il n'y a qu'une seule catégorie).

    J'ai ensuite fait la requête suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT t.IDItem
    FROM ItemCategory t
    WHERE t.IDItem IN
      (SELECT t0.IDItem
      FROM ItemCategory t0
      WHERE t0.IDCategory='Category1')
    AND t.IDItem IN
      (SELECT t1.IDItem
      FROM ItemCategory t1
      WHERE t1.IDCategory='Category2')
    Malheureusement, le temps d'exécution de la requête est énorme et je trouve que c'est bête de ne pas utiliser les ensembles d'IDItem calculés pour chaque catégorie...

    Et dans un second temps, je récupère les Items de la façon suivante :
    SELECT *
    FROM Item i
    WHERE i.IDItem IN SOUS-REQUETE
    Avec SOUS-REQUETE la requête définie précédemment.

    Le problème est que, même avec une seule catégorie, la réponse n'arrive qu'au bout de 30 secondes, ce qui est énorme pour une page web...

    J'utilise SQLite parce que mon hébergeur n'accepte que des bases MySQL de taille inférieure à 100mo (et j'en ai 30...). J'ai fait des tests en local avec MySQL et pour la même requête, ça met 150s.

    Quelqu'un aurait des conseils pour optimiser mes requêtes?

  2. #2
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 218
    Points : 28 169
    Points
    28 169
    Par défaut
    Peut-être avec une requete du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT t1.* FROM Item t1
    JOIN ItemCategory t2 ON t1.IDItem=t2.IDItem
    WHERE t2.IDCategory='Category1' OR t2.IDCategory='Category2'
    Ou, si tu as plus de 2 catégories et que tu ne veux pas te tapper une série de OR dans le WHERE :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT t1.* FROM Item t1
    JOIN ItemCategory t2 ON t1.IDItem=t2.IDItem
    WHERE t2.IDCategory IN ('Category1','Category2','Category3',.....)

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    61
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 61
    Points : 33
    Points
    33
    Par défaut
    Merci beaucoup pour la réponse

    Le problème est que l'Item doit être dans toutes les catégories de l'ensemble (de catégories), et pas seulement l'une des catégories

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 849
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 849
    Points : 52 978
    Points
    52 978
    Billets dans le blog
    6
    Par défaut
    Que d'horreur dans votre requête !!!

    GROUP BY ne sert qu'à faire des sous ensemble de données dans le cas d'un calcul d'agrégat (SUM, COUNT, MAX...)relatif à un sous ensemble.
    Apprenez SQL et les groupages : http://sqlpro.developpez.com/cours/sqlaz/ensembles/

    HAVING sert à filtrer des données calculées provenant d'un calcul d'agrégat

    SELECT * est à proscrire si vous voulez des performances : mettez des colonnes explicites et le minimum requis

    Enfin, dans ce cas vous devez faire une division relationnelle. Voir l'article que j'ai écrit à ce sujet : http://sqlpro.developpez.com/cours/divrelationnelle/

    A +

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    61
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 61
    Points : 33
    Points
    33
    Par défaut
    Merci SQLPro pour votre réponse !

    La division relationnelle est ce que j'essaie de faire. Ne l'ayant vu qu'en théorie en cours de BD il y a quelques années, je l'avais oublié. J'ai été choqué en apprenant qu'elle était rarement (voire pas) implantée.

    La fonction HAVING ne sert que pour les agrégats, oui, je sais, j'étais désespéré alors j'ai essayé tout et n'importe quoi. Par contre, ça m'a étonné que les IDCategory=machin passent

    Merci pour l'info sur le SELECT *, on ne m'avait jamais dit que c'était gourmand

    Je vais tenter la solution de division avec un INTERSECT, merci encore pour la suggestion !


    EDIT 1: Après essai de division avec un INTERSECT, c'est plus long que ma solution (qui marche)... Je vais essayer de faire une cascade de select pour voir si ça va plus vite.

    EDIT 2 : Ce qui n'est pas possible comme je le pensais ou qui n'apporte rien pour l'autre façon à laquelle j'ai pensé...

  6. #6
    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 386
    Points
    18 386
    Par défaut
    Essayez ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      SELECT IDItem
        FROM ItemCategory
       WHERE IDCategory IN ('Category1', 'Category2')
    GROUP BY IDItem
      HAVING count(distinct IDCategory) = 2
    ORDER BY IDItem ASC;

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    61
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 61
    Points : 33
    Points
    33
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Essayez ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      SELECT IDItem
        FROM ItemCategory
       WHERE IDCategory IN ('Category1', 'Category2')
    GROUP BY IDItem
      HAVING count(distinct IDCategory) = 2
    ORDER BY IDItem ASC;
    Merci ! Avec cette requête, le temps de calcul a été divisé par 2

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

Discussions similaires

  1. [Access] Optimisation performance requête - Index
    Par fdraven dans le forum Access
    Réponses: 11
    Dernier message: 12/08/2005, 14h30
  2. Optimisation de requête avec Tkprof
    Par stingrayjo dans le forum Oracle
    Réponses: 3
    Dernier message: 04/07/2005, 09h50
  3. Optimiser une requête SQL d'un moteur de recherche
    Par kibodio dans le forum Langage SQL
    Réponses: 2
    Dernier message: 06/03/2005, 20h55
  4. optimisation des requêtes
    Par yech dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 21/09/2004, 19h03
  5. Optimisation de requête
    Par olivierN dans le forum SQL
    Réponses: 10
    Dernier message: 16/12/2003, 10h09

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