使用其他SELECT优化JOIN SQL查询

时间:2010-09-15 11:35:12

标签: sql mysql query-optimization

我需要一个查询,为每个产品选择一个GROUP BY phi.id_product)图片,此图片必须是最高优先级的图片(带有SELECT语句的内部ORDER BY

优先级存储在名为product_has_image

的N:M关系表中

我已经创建了一个查询,但执行需要大约3秒钟,我需要对其进行优化。这是:

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

我认为在此查询中重要的索引是:

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)

大多数情况下,使用排序所需的SELECT语句来加入表。

加入LEFT JOIN [product_has_image] phi ON p.id = phi.id_product速度要快得多,但不会为图像分配最高优先级。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

重新格式化敏感度。 。

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

没有看到执行计划或DDL,我猜(不寒而栗)问题可能是内部选择/排序。如果您创建视图

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

然后你可以用那个视图上的SELECT ... INNER JOIN替换那个内部的SELECT ... ORDER BY。这会降低基数,所以我希望它能跑得更快。

发布DDL会有所帮助。

答案 1 :(得分:0)

我可能会尝试这样做:

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

答案 2 :(得分:0)

现在无法测试,但是不可能这样做吗?

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

通过phi.priority以常规连接和顺序进行。