2010-09-15 6 views
0

supplémentaire je besoin d'une requête qui sélectionnera juste une image pour chaque produit et cette image (GROUP BY phi.id_product) doivent être celui avec le la plus haute priorité (déclaration intérieure SELECT avec ORDER BY).Optimize REJOIGNEZ requête SQL avec SELECT

La priorité est stockée dans N: table M relation appelé product_has_image

J'ai créé une requête, mais il tooks environ 3 secondes pour exécuter et je dois optimiser. Ici, il est:

SELECT p.*, i.id AS imageid 
FROM `product` p JOIN `category` c on c.`id` = p.`id_category` 
LEFT OUTER JOIN (SELECT id_product, id_image FROM 
`product_has_image` ORDER BY priority DESC) phi ON p.id = phi.id_product 
LEFT OUTER JOIN `image` i ON phi.id_image = i.id 
WHERE (c.`id_parent` = 2 OR c.`id` = 2) 
GROUP BY phi.id_product 

index que je trouve important dans cette requête sont:

image (PRIMARY id) 
product_has_image (PRIMARY id_product, id_image; INDEX id_product; INDEX id_image) 
product (PRIMARY id, id_category; INDEX id_category) 
category (PRIMARY id; INDEX id_parent) 

La plupart du temps se joindre aux tables en utilisant l'instruction SELECT qui est nécessaire pour le tri.

L'association avec LEFT JOIN [product_has_image] phi ON p.id = phi.id_product est beaucoup plus rapide, mais n'attribue pas l'image avec la plus haute priorité.

Toute aide serait appréciée.

+0

Pouvez-vous publier le plan d'exécution? –

+0

Salut, merci pour votre réponse. Après avoir créé la vue, il faut environ 0,3 à 0,5 secondes sur ma machine et c'est encore plus rapide sur le serveur. –

Répondre

1

Reformaté pour la sensibilité. . .

SELECT p.*, i.id AS imageid 
FROM `product` p 
INNER JOIN `category` c on (c.`id` = p.`id_category`) 
LEFT OUTER JOIN (SELECT id_product, id_image 
       FROM `product_has_image` 
       ORDER BY priority DESC) phi 
      ON (p.id = phi.id_product) 
LEFT OUTER JOIN `image` i 
      ON (phi.id_image = i.id) 
WHERE (c.`id_parent` = 2 OR c.`id` = 2) 
GROUP BY phi.id_product 

Sans voir un plan d'exécution ou DDL, je suppose (frisson) que le problème est susceptible d'être le select/trier intérieure. Si vous créez une vue

create view highest_priority_images as 
select id_product, max(priority) 
from product_has_image 
group by id_product 

Ensuite, vous pouvez le remplacer SELECT ... ORDER BY avec un intérieur SELECT ... INNER JOIN sur ce point de vue. Cela réduirait la cardinalité, donc je m'attendrais à ce qu'il s'exécute plus vite.

La publication DDL aiderait.

0

Je probablement essayer de le faire comme ceci:

SELECT p.*, i.id AS imageid 
FROM `product` p 
    INNER JOIN `category` c ON c.id = p.id_category 

    /* a list of `id_product`s with their highest priorities 
    from `product_has_image` */ 
    LEFT OUTER JOIN (
    SELECT id_product, MAX(priority) AS max_priority 
    FROM `product_has_image` 
    GROUP BY id_product 
) m ON p.id = m.id_product 

    /* now joining `product_has_image` again, using 
    m.`max_priority` for additional filtering */ 
    LEFT OUTER JOIN `product_has_image` phi 
    ON p.id = phi.id_product AND m.max_priority = phi.priority 

    /* if you only select `id` from `image`, you can use 
    phi.`id_image` instead and remove this join */ 
    LEFT OUTER JOIN `image` i ON phi.id_image = i.id 

WHERE c.id_parent = 2 OR c.id = 2 
0

ne peut pas tester maintenant, mais serait-il pas possible de le faire?

SELECT p.*, i.id AS imageid 
FROM `product` p JOIN `category` c on c.`id` = p.`id_category` 
LEFT JOIN `product_has_image` phi ON p.id = phi.id_product 
LEFT OUTER JOIN `image` i ON phi.id_image = i.id 
WHERE (c.`id_parent` = 2 OR c.`id` = 2) 
GROUP BY phi.id_product 
ORDER BY phi.priority DESC 

Faites-le dans une jointure régulière et commandez par phi.priority.