将SQL重写为JOINS而不是子查询

时间:2013-07-17 17:57:15

标签: sql query-optimization derby

我有以下查询。它使用三个子查询并且经常执行,所以我想将查询重写为JOIN。虽然我的价值观不正确,但我有没有想过如何成功地重写查询?我试图这样做?

使用子查询查询

SELECT  PRODUCT.ID 
FROM    PRODUCT WHERE (
            COALESCE((SELECT SUM(AMOUNT) FROM CORRECTION WHERE CORRECTION.PRODUCT_ID = PRODUCT.ID),0)
            - COALESCE((SELECT SUM(AMOUNT) FROM ORDERROW WHERE ORDERROW.PRODUCTID = PRODUCT.ID),0)
            + COALESCE((SELECT SUM(AMOUNTOFPACKAGES * AMOUNTPERPACKAGE) FROM DELIVERYROW WHERE DELIVERYROW.PRODUCTID = PRODUCT.ID),0)
            ) > 0

使用联接进行虚假查询

SELECT  PRODUCT.ID
FROM    PRODUCT
LEFT JOIN CORRECTION  ON CORRECTION.PRODUCT_ID = PRODUCT.ID
LEFT JOIN ORDERROW    ON ORDERROW.PRODUCTID = PRODUCT.ID
LEFT JOIN DELIVERYROW ON DELIVERYROW.PRODUCTID = PRODUCT.ID
GROUP BY PRODUCT.ID
HAVING  (COALESCE(SUM(CORRECTION.AMOUNT),0)
        - COALESCE(SUM(ORDERROW.AMOUNT),0)
        + COALESCE(SUM(DELIVERYROW.AMOUNTOFPACKAGES * DELIVERYROW.AMOUNTPERPACKAGE),0) 
        ) > 0

1 个答案:

答案 0 :(得分:2)

重写的问题是每个连接表中给定产品可能有很多行,总结果集将是Cartesian product;它将包含与每个连接表中匹配行数相乘的行数。

您可以确保每个联接表每个产品最多只有一行:

SELECT  PRODUCT.ID
FROM    PRODUCT
LEFT JOIN (SELECT PRODUCTID, SUM(AMOUNT) AS AMOUNT 
           FROM CORRECTION GROUP BY PRODUCTID) AS C
  ON C.PRODUCT_ID = PRODUCT.ID
LEFT JOIN (SELECT PRODUCTID, SUM(AMOUNT) AS AMOUNT 
           FROM ORDERROW GROUP BY PRODUCTID) AS O
  ON O.PRODUCTID = PRODUCT.ID
LEFT JOIN (SELECT PRODUCTID, SUM(AMOUNTOFPACKAGES * AMOUNTPERPACKAGE) AS AMOUNT 
           FROM DELIVERYROW GROUP BY PRODUCTID) AS D
  ON D.PRODUCTID = PRODUCT.ID
WHERE COALESCE(C.AMOUNT,0)
    - COALESCE(O.AMOUNT,0)
    + COALESCE(D.AMOUNT,0) > 0;

此解决方案在技术上仍然使用子查询,但派生表子查询通常比您使用的相关子查询便宜。与往常一样,您只能通过测试确定它将如何影响您的数据。