这个查询看起来优化了吗?
我正在为一个应用程序编写查询,该应用程序需要列出所有产品以及购买次数。
我想出了这个方法,它可以工作,但是我不太确定它是如何优化的。由于大量使用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
它的性能应大致等同于联接形式。如果没有,请告诉我。