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 une requete qui prend une quarantaine de minute.


Sujet :

Requêtes MySQL

  1. #1
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut Optimiser une requete qui prend une quarantaine de minute.
    Bonjour,


    je dois faire une requête complexe en MySQL sur des tables relativement volumineuses. Rien que la première partie de ma requête prend plus de 40 min à tourner en local...

    Donc si vous pouviez m'aider à l'optimiser ça serait supra cool.

    Pour cette requête, j'utilise 4 tables dont voici les DESCRIBE :

    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
     
    mysql> describe biset_cont_tag;
    +-----------+-------------+------+-----+---------+-------+
    | Field     | Type        | Null | Key | Default | Extra |
    +-----------+-------------+------+-----+---------+-------+
    | bisetID   | int(11)     | YES  | MUL | 0       |       | 
    | tagID     | int(11)     | YES  |     | 0       |       | 
    | discr_met | varchar(30) | YES  |     |         |       | 
    | threshold | int(11)     | YES  |     | 0       |       | 
    +-----------+-------------+------+-----+---------+-------+
    4 rows in set (0.00 sec)
     
    mysql> describe hs_virtual_observed_tag;
    +------------------+--------+------+-----+---------+-------+
    | Field            | Type   | Null | Key | Default | Extra |
    +------------------+--------+------+-----+---------+-------+
    | HsObservedTag_id | int(8) | NO   | PRI | NULL    |       | 
    | HsVirtualTag_id  | int(8) | NO   | PRI | NULL    |       | 
    +------------------+--------+------+-----+---------+-------+
    2 rows in set (0.00 sec)
     
    mysql> describe hs_transcript_go;
    +----------------------+-------------+------+-----+---------+-------+
    | Field                | Type        | Null | Key | Default | Extra |
    +----------------------+-------------+------+-----+---------+-------+
    | Id                   | int(11)     | NO   |     | 0       |       | 
    | gene_product         | varchar(15) | YES  | MUL |         |       | 
    | description          | mediumtext  | YES  |     | NULL    |       | 
    | gi_ref               | int(11)     | YES  |     | 0       |       | 
    | refseq               | varchar(20) | YES  |     |         |       | 
    | HsVirtualTag_id      | int(11)     | YES  |     | 0       |       | 
    | gene_product_aliases | text        | YES  |     | NULL    |       | 
    +----------------------+-------------+------+-----+---------+-------+
    7 rows in set (0.00 sec)
     
    mysql> DESCRIBE hs_transcription_factor;
    +---------------+-------------+------+-----+---------+----------------+
    | Field         | Type        | Null | Key | Default | Extra          |
    +---------------+-------------+------+-----+---------+----------------+
    | TF_id         | int(8)      | NO   | PRI | NULL    | auto_increment | 
    | transfac_name | varchar(15) | NO   |     | NULL    |                | 
    | gene_product  | varchar(15) | NO   |     | NULL    |                | 
    | mtx_id        | int(8)      | NO   |     | NULL    |                | 
    | core_position | int(2)      | NO   |     | NULL    |                | 
    +---------------+-------------+------+-----+---------+----------------+
    5 rows in set (0.00 sec)
    et voici ma requete :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SELECT DISTINCT bisetID 
    FROM biset_cont_tag, hs_virtual_observed_tag 
    WHERE tagID = hsobservedtag_id 
    AND hsvirtualtag_id IN (SELECT DISTINCT hsvirtualtag_id 
    FROM hs_transcript_go AS gene, hs_transcription_factor AS TF 
    WHERE gene.gene_product = TF.gene_product);
    Cette requête a mis 41min a me renvoyer le résultat (sans le DISTINCT que j'avais oublié), et 47sec en limitant les résultats à 10 enregistrements.

    Sachant que cette requête ne me permet que de récupérer la moitié de mon résultat, je panique un peu!

    J'ai essayé en éliminant la sous requête au profit de deux jointures, mais c'est plus long (de même qu'en éliminant la jointure au profit d'une deuxième sous requête).

    En cherchant sur le web, je vois qu'il est souvent question d'indexation pour optimiser les requêtes, mais je ne sais pas quel champs indexer ?

    Tous les conseils seront les bienvenues.

    Merci d'avance

  2. #2
    Membre expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    Saluton,
    Déjà, utilisons la bonne syntaxe de jointure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT DISTINCT bisetID 
    FROM biset_cont_tag b
    INNER JOIN  hs_virtual_observed_tag h
    ON b.tagID = h.hsobservedtag_id 
    WHERE H.hsvirtualtag_id IN (SELECT DISTINCT hsvirtualtag_id 
    FROM hs_transcript_go g
    INNER JOIN  hs_transcription_factor TF 
    ON ge.gene_product = TF.gene_product);
    Mais il faudra m'expliquer à quoi sert la deuxième jointure, celle de la sous-requête.

  3. #3
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    merci pour la syntaxe, ça faisait un bout de temps que j'avais pas fait de MySQL, ça part vite mais j'avais pas le souvenir de cette syntaxe...

    la deuxième jointure sert à filtrer les gene_product de la table hs_transcript_go : dans la table hs_transcription_factor, on a tous les gene_product correspondant à des facteurs de transcription et dans la tables hs_transcript_go, il y en a beaucoup plus.
    Je ne veux que les hsvirtualtag_id correspondant à des facteurs de transcription, d'où la jointure.

    je sais pas si c'est très clair. Je veux bien explicité d'avantage, mais le domaine d'application est assez pointu...

    EDIT: j'ai testé avec la bonne syntaxe de jointure, ça gagne un dixième de seconde en limitant les résultats à 10...

  4. #4
    Membre expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    Dans l'idéal il faudrait que les colonnes suivantes soient des index :
    b.tagID
    h.hsobservedtag_id
    TF.hsvirtualtag_id
    ge.gene_product
    TF.gene_product
    Normalement aussi, transformer la sous-requête en jointure devrait améliorer les performances.
    En tout cas c'est ce qui est habituellement prescrit.

  5. #5
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    bon, alors question : est il possible d'ajouter des index à des tables qui sont déjà en production?

    je m'explique, je bosse sur une base de données déjà en production, je dois lui ajouter des tables pour pouvoir répondre à de nouvelles requêtes (en autre celle que j'essaie d'optimiser).
    Du coup, ajouter un index sur la table TF ne pose pas de problème (puisque c'est moi qui vient de la créer), mais pour les tables déjà en prod, est ce possible sans problème?
    Y'a t-il une astuce pour pas tout faire planter?

  6. #6
    Membre expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    MySQL est un SGBDR ACID, qui supporte les requêtes de description de données (LDD) en l'occurrence il s'agit de syntaxe de type ALTER TABLE.
    Une conséquence possible de la création d'index est le ralentissement des requêtes INSERT, UPDATE, REPLACE et DELETE, par contre ça peut accélérer de nombreuses requêtes SELECT.
    Avec des nuances suivant que les tables sont de type MyISAM ou InnoDB.
    Comme toujours, il vaut mieux faire une sauvegarde de la base avant toute chose.

  7. #7
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    je suis en train d'essayer de transformer la sous requête en jointure avec ta syntaxe, mais j'ai du mal à visualiser : je vois pas comment on peut joindre plus de deux tables avec cette syntaxe... et j'arrive pas à trouvé ma réponse dans le site dev.mysql.com

  8. #8
    Membre expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT DISTINCT bisetID 
    FROM biset_cont_tag b
    INNER JOIN  hs_virtual_observed_tag h
    ON b.tagID = h.hsobservedtag_id 
    INNER JOIN hs_transcript_go g
    ON h.hsvirtualtag_id=g.hsvirtualtag_id 
    INNER JOIN  hs_transcription_factor TF 
    ON ge.gene_product = TF.gene_product;
    Ça doit être qqe chose dans ce genre là, non ?

  9. #9
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Citation Envoyé par Maljuna Kris Voir le message
    MySQL est un SGBDR ACID, qui supporte les requêtes de description de données (LDD) en l'occurrence il s'agit de syntaxe de type ALTER TABLE.
    Une conséquence possible de la création d'index est le ralentissement des requêtes INSERT, UPDATE, REPLACE et DELETE, par contre ça peut accélérer de nombreuses requêtes SELECT.
    Avec des nuances suivant que les tables sont de type MyISAM ou InnoDB.
    Comme toujours, il vaut mieux faire une sauvegarde de la base avant toute chose.
    il s'agit de table MyISAM.
    du coup, tu me conseilles de faire une sauvegarde de la base de données, puis de faire des ALTER TABLE pour ajouter les index genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ALTER TABLE hs_transcript_go ADD INDEX gene_product_index gene_product
    et après, il suffit de faire les mêmes requêtes mais ça devraient être plus rapide (pour mes SELECT), c'est ça?

    Je vais tester sur une copie de la base de données avant de le faire sur la base qui est en prod.

  10. #10
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Citation Envoyé par Maljuna Kris Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT DISTINCT bisetID 
    FROM biset_cont_tag b
    INNER JOIN  hs_virtual_observed_tag h
    ON b.tagID = h.hsobservedtag_id 
    INNER JOIN hs_transcript_go g
    ON H.hsvirtualtag_id=g.hsvirtualtag_id 
    INNER JOIN  hs_transcription_factor TF 
    ON ge.gene_product = TF.gene_product;
    Ça doit être qqe chose dans ce genre là, non ?
    AH ok, on peut faire des INNER JOIN en cascade après un seul FROM. Merci beaucoup, je teste immédiatement

  11. #11
    Membre expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    Attention il y avait une faute de frappe, un H. pour un h.
    Mais apparemment tu m'as cité avant que je corrige mon post.

  12. #12
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    YAHOU! avec ta super requête pleine de jointure, je passe de 12sec64 à 1sec59 en limitant les résultats à 10!!

    déjà rien que ça, c'est supra cool! (je vais pouvoir écrire des vrai jointure à présent, merci )

    bon, je vais quand même me pencher sur cette histoire d'index...

  13. #13
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Citation Envoyé par Maljuna Kris Voir le message
    Attention il y avait une faute de frappe, un H. pour un h.
    Mais apparemment tu m'as cité avant que je corrige mon post.
    oui, j'avais corrigé dans MySQL (aussi un ge pour un g)

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/11/2014, 18h02
  2. Réponses: 4
    Dernier message: 27/03/2013, 14h56
  3. problème d'une invite qui prend une date en paramètre
    Par soufiane669 dans le forum iReport
    Réponses: 1
    Dernier message: 24/09/2010, 17h48
  4. Réponses: 2
    Dernier message: 05/05/2009, 10h39
  5. Réponses: 2
    Dernier message: 08/01/2009, 10h12

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