这个查询看起来优化了吗?

时间:2020-03-06 15:01:03  来源:igfitidea点击:

我正在为一个应用程序编写查询,该应用程序需要列出所有产品以及购买次数。

我想出了这个方法,它可以工作,但是我不太确定它是如何优化的。由于大量使用ORM,我的SQL确实很生锈,但是在这种情况下,查询是一种更为优雅的解决方案。

我们可以在查询中发现任何错误(明智的做法)吗?

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

更新

这是针对MySQL

解决方案

它给我们正确的答案吗?

除了只修改它以摆脱内部查询中的SELECT之外,我看不到任何问题。

好吧,我们有" LEFT OUTER JOIN",这可能是性能问题,具体取决于数据库。
上次我记得它在MySQL上导致了地狱,而在SQLite中却不存在。我认为Oracle可以很好地处理它,而且我猜DB和MSSQL也可以。

编辑:如果我没记错的话,在MySQL上,LEFT OUTER JOIN的速度可能要慢几个数量级,但是如果我在这里过时,请纠正我:)

未经测试的代码,但请尝试:

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,我们只有一个描述。

括号可能需要放在INNER JOIN周围。

我不确定"(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

这是针对我们中有嵌套障碍的人的解决方案。 (当我开始嵌套联接时,我很困惑)

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上测试了Mike和我的解决方案,并且查询计划是相同的。我不能代表MySql,但是如果要使用MS SQL Server,我们可能会发现所有三种解决方案的性能都相当。如果是这种情况,我想我们应该选择哪种解决方案对我们来说最清晰。

这是一个子查询表单。

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

它的性能应大致等同于联接形式。如果没有,请告诉我。