2013-09-28 4 views
0

Je montre une requête de vente qui impliquait plusieurs tables de suivi. (Ne montrant que des données)Sous-requête mysql extrêmement lente

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 

cette requête prend 0.650s. Je veux ajouter dans différentes colonnes, sous-requête, je retourne le dernier état de la vente distribué par étapes. Quelque chose comme:

id_sale | ... | last_state_of_stage_1 | last_state_of_stage_2 | last_state_of_stage_3 
01  | ... | new_sale    | distributed_sale  | canceled_sale 
02  | ... | new_sale    | distributed_sale  | invoiced_sale 
... 

Les états et les étapes de chaque vente sont stockés dans une histoire:

sale_history 
------------ 
id_history int -- primary key 
id_sale int 
id_state_detail int -- contains the states id's and logic 
observation tinytext 
date_history datetime 
id_user int 
id_profile int 
... 

index:

CREATE INDEX indx_id_sale USING BTREE ON sale_history (id_sale); 
CREATE INDEX indx_id_state_detail USING BTREE ON sale_history (id_state_detail); 

Chaque histoire a une moyenne de 25 dossiers à vendre. Pour obtenir le statut de la vente, je pense qu'un sous-requête (et pour chacune des étapes):

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 

IFNULL((SELECT state_name 
      FROM sale_history veh 
      INNER JOIN state_detail vec ON vec.id_state_detail = veh.id_state_detail 
      INNER JOIN sale_state ve ON ve.iid_sale_state= vec.iid_sale_state 
      WHERE veh.id_sale = v.id_sale 
      AND vec.iid_sale_stage = 5 
      AND veh.flag = 1 
      ORDER BY veh.id_history DESC 
      LIMIT 1 
),'x') last_state_of_stage_1 

FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 

mais ce retard 115.985s sous_requête! Je me demande parce que cela prend si longtemps?

EDIT 30-09-13

par les commentaires de Fancypants, j'ai fait quelques changements qui a grandement amélioré la vitesse de la requête:

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 
    IFNULL(ve5.state_name,'x') last_state_of_stage_1 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
LEFT JOIN sale_history veh5 ON veh5.id_sale = v.id_sale AND veh5.flag = 1 AND veh5.id_history = (SELECT MAX(sh.id_history) 
                                                    FROM sale_history sh 
                                                    INNER JOIN state_detail vecx ON vecx.id_state_detail = sh.id_state_detail 
                                                    INNER JOIN sale_state vex ON vex.iid_sale_state= vecx.iid_sale_state 
                                                    WHERE sh.id_sale = v.id_sale AND sh.id_sale = veh5.id_sale 
                                                    AND sh.flag = 1 
                                                    AND vecx.iid_sale_stage = 5 
                                                    ) 
LEFT JOIN state_detail vec5 ON vec5.id_state_detail = veh5.id_state_detail 
LEFT JOIN sale_state ve5 ON ve5.iid_sale_state = vec5.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 
AND EXISTS(SELECT '1' 
       FROM sale_activity veh 
       INNER JOIN state_detail vec ON vec.id_state_detail = veh.id_state_detail 
       INNER JOIN sale_state ve ON ve.iid_sale_state= vec.iid_sale_state 
       WHERE id_sale = v.id_sale 
       AND iid_sale_stage = 4 
       LIMIT 1) 

prendre maintenant 0.609s à afficher les données, merci!

Répondre

1

S'il vous plaît laissez-vous tenter si cette requête fonctionne mieux:

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 
    COALESCE(state_name, 'x') last_state_of_stage_1 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
INNER JOIN sale_history veh ON veh.id_sale = v.id_sale AND vec.iid_sale_stage = 5 AND veh.flag = 1 
WHERE v.flag = 1 
AND v.id_headquarters_detail = 2 
AND veh.id_history = (SELECT MAX(id_history) FROM sale_history sh WHERE sh.id_sale = veh.id_sale); 

Si elle n'a pas (en supposant qu'il produit des résultats corrects), exécutez à nouveau avec EXPLAIN devant et afficher les résultats, s'il vous plaît.

+0

merci !, j'ai édité ma question – csotelo

1

La requête interne est exécutée plusieurs fois pour chaque ligne de votre table, augmentant exponentiellement le temps de votre requête (s'aggrave avec plus d'enregistrements). C'est pourquoi les sous-requêtes doivent être traitées avec soin dans les applications du monde réel.

Je vous suggère d'essayer une approche différente de cette requête (il existe de nombreux cas où une combinaison complexe de JOINs peut remplacer une sous-requête).

Questions connexes