Этот запрос выглядит оптимизированным? - PullRequest
1 голос
/ 02 октября 2008

Я пишу запрос для приложения, в котором необходимо перечислить все продукты с указанием количества их покупок.

Я придумал это, и оно работает, но я не слишком уверен, насколько оно оптимизировано. Мой SQL действительно ржавый из-за интенсивного использования ORM, но в этом случае запрос является гораздо более элегантным решением.

Можете ли вы найти что-то не так (подход мудрый) с запросом?


SELECT  products.id, 
        products.long_name AS name, 
        count(oi.order_id) AS sold
FROM    products
LEFT OUTER JOIN 
      ( SELECT * FROM orderitems
        INNER JOIN orders ON orderitems.order_id = orders.id 
        AND orders.paid = 1 ) AS oi 
      ON oi.product_id = products.id
GROUP BY products.id

Схема (с соответствующими полями) выглядит следующим образом:

*orders*      id, paid
*orderitems*  order_id, product_id
*products*    id

UPDATE

Это для MySQL

Ответы [ 6 ]

3 голосов
/ 02 октября 2008

Я не уверен насчет "(SELECT *" ... бизнеса.

Это выполняется (всегда хорошее начало), и я думаю, что эквивалентно тому, что было опубликовано.

SELECT  products.id, 
    products.long_name AS name, 
    count(oi.order_id) AS sold
FROM    products
LEFT OUTER JOIN
    orderitems AS oi
        INNER JOIN 
            orders 
            ON oi.order_id = orders.id AND orders.paid = 1
    ON oi.product_id = products.id
GROUP BY products.id
2 голосов
/ 02 октября 2008

Вот решение для тех из нас, кто с нарушениями вложенности. (Я так растерялся, когда начинаю вкладывать объединения)

SELECT  products.id, 
    products.long_name AS name, 
    count(oi.order_id) AS sold
FROM orders 
    INNER JOIN orderitems  AS oi ON oi.order_id = orders.id AND orders.paid = 1
    RIGHT JOIN products ON oi.product_id = products.id
GROUP BY products.id

Однако я протестировал ваше решение, Майк и мое, на MS SQL Server, и планы запросов идентичны. Я не могу говорить за MySql, но если MS SQL Server что-то может пройти, вы можете найти производительность всех трех решений эквивалентны. Если это так, я думаю, вы выбираете, какое решение вам наиболее понятно.

1 голос
/ 02 октября 2008

Это дает вам правильный ответ?

За исключением простой модификации, чтобы избавиться от SELECT во внутреннем запросе, я не вижу в этом ничего плохого.

0 голосов
/ 03 октября 2008

Вот форма подзапроса.

SELECT
  p.id,
  p.long_name AS name,
  (SELECT COUNT(*) FROM OrderItems oi WHERE oi.order_id in
    (SELECT o.id FROM Orders o WHERE o.Paid = 1 AND o.Product_id = p.id)
  ) as sold
FROM Products p

Должно быть примерно эквивалентно форме соединения. Если это не так, дайте мне знать.

0 голосов
/ 02 октября 2008

Не проверенный код, но попробуйте:

SELECT  products.id,
    MIN(products.long_name) AS name, 
    count(oi.order_id) AS sold
FROM    (products
LEFT OUTER JOIN orderitemss AS oi ON oi.product_id = products.id)
INNER JOIN orders AS o ON oi.order_id = o.id 
WHERE orders.paid = 1
GROUP BY products.id

Я не знаю, нужны ли скобки для LEFT OUTER JOIN, ни в том случае, если MySQL допускает несколько соединений, однако MIN (products.long_name) дает только описание, поскольку для каждого products.id у вас есть только одно описание .

Возможно, круглые скобки должны быть вокруг ВНУТРЕННЕГО СОЕДИНЕНИЯ.

0 голосов
/ 02 октября 2008

Ну, у вас есть "LEFT OUTER JOIN", который может быть проблемой производительности в зависимости от вашей базы данных. В прошлый раз я помню, что это вызвало ад в MySQL, а в SQLite его нет. Я думаю, что Oracle может справиться с этим нормально, и я думаю, DB и MSSQL тоже.

РЕДАКТИРОВАТЬ: Если я правильно помню, LEFT OUTER JOIN может быть медленнее на MySQL, но, пожалуйста, исправьте меня, если я устарел здесь:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...