Оптимизируйте запрос SQL JOIN с дополнительным SELECT

0

Мне нужен запрос, который будет выбирать только одно (GROUP BY phi.id_product) изображение для каждого продукта, и это изображение должно быть тем, у кого наивысший приоритет (внутренний SELECT с инструкцией ORDER BY).

Приоритет сохраняется в таблице отношений N: M, называемой product_has_image

Я создал запрос, но для выполнения потребовалось около 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 выполняется намного быстрее, но не назначает изображение с наивысшим приоритетом.

Любая помощь будет оценена.

  • 0
    Можете ли вы опубликовать план выполнения?
  • 0
    Привет, спасибо за ответ. После создания представления на моем компьютере это занимает около 0,3 - 0,5 секунды, а на сервере - еще быстрее.
Теги:
query-optimization

3 ответа

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, я бы догадался (содрогнулся), что проблема, вероятно, будет внутренней select/sort. Если вы создаете представление

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

Затем вы можете заменить этот внутренний SELECT... ORDER BY с помощью SELECT... INNER JOIN на этом представлении. Это уменьшит мощность, поэтому я ожидаю, что он будет работать быстрее.

Проводка DDL поможет.

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
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.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню