【问题标题】:SUM() recursion issue when joining tables连接表时的 SUM() 递归问题
【发布时间】:2015-06-23 15:22:58
【问题描述】:

我的一个查询存在性能问题。

慢查询:

SELECT
    Stock.StockID,
    Stock.sku AS SKU, 
    Stock.ProductName AS PRODUCT, 
    SUM(OrderItems.[quantity-purchased]) AS Qty 
FROM 
    Orders, OrderItems, CMRC_Stock as Stock
WHERE
    Orders.[status] = 'PRINTED' AND 
    Orders.[order-id] = OrderItems.[order-id] AND
    (Stock.SKU = OrderItems.SKU OR
    OrderItems.sku IN (SELECT SKU FROM AlternateSKUS WHERE StockID = Stock.StockID) OR
    Stock.BarCode = OrderItems.SKU) AND
    Orders.channelId != 21

GROUP BY Stock.StockID, Stock.sku, Stock.ProductName 
ORDER BY Qty DESC, Stock.sku

返回结果大约需要 11 秒。

我试图优化查询,从 WHERE 子句中删除嵌套的 SELECT 并想出了这个:

SELECT
    Stock.StockID,
    Stock.sku AS SKU, 
    Stock.ProductName AS PRODUCT, 
    SUM(OrderItems.[quantity-purchased]) AS Qty 
FROM
    Orders

FULL    OUTER JOIN OrderItems ON Orders.[order-id] = OrderItems.[order-id]
LEFT    OUTER JOIN CMRC_Stock as Stock ON OrderItems.sku = Stock.SKU
LEFT    OUTER JOIN AlternateSKUS ON AlternateSKUS.StockID = Stock.StockID

WHERE
    Orders.[status] = 'PRINTED' AND
    (Stock.SKU = OrderItems.SKU OR 
        AlternateSKUS.SKU = OrderItems.sku OR
        Stock.BarCode = OrderItems.SKU) AND
    Orders.channelId != 21

GROUP BY Stock.StockID, Stock.sku, Stock.ProductName 
ORDER BY Qty DESC, Stock.sku

它的运行速度要快得多

但是有一个问题。看来我的 SUM() 函数存在递归问题,因为它将正确的数量乘以相同 StockID 存在的“AlternateSKU”记录数。

例如,如果有 1 个订单,对于 1 个 OrderItem,则将其 (QTY) 计为 4,因为它有 4 个 AlternateSKU。如果为同一商品购买了 2 个数量,则 QTY 将返回 8。如果同一 OrderItem 有其他订单,则商品数量乘以该商品的 AlternateSKU 记录数量。 E.G 3 个单独的 OrderItems 属于单独的 Orders 将产生 12 个相同商品的数量。

我意识到这最终归结于设计不佳的架构,但是我必须使用我所拥有的。

我该如何解决这个问题?

【问题讨论】:

  • 在编写查询时始终使用显式连接 (table1 INNER JOIN table2 ON)。使用“table1,table2,table3”语法会导致笛卡尔积错误。
  • @Jeremy,您能详细说明一下吗?我的 SQL 经验相当基础。
  • Here 很好地解释了@Jeremy 所指的 JOIN 语法问题。
  • 啊,对了,明白了。感谢您的提示。

标签: sql sql-server database performance


【解决方案1】:

这一切都归结为[CMRC_Stock][OrderItems] 之间的关系。库存 SKU 可以包含多个替代 SKU。然后每个订单商品的数量将乘以替代 SKU 的数量。

我在下面所做的是重构您的原始查询,以便首先检索不同的 SKU/库存 ID 列表,然后可以从中将 [OrderItems] 连接到 [CMRC_Stock]

WITH StockSKUs([StockID],[SKU]) AS (
    SELECT 
        [StockID],[SKU]
    FROM [CMRC_Stock]
    UNION
    SELECT
        [StockID],[BarCode]
    FROM [CMRC_Stock]
    UNION
    SELECT
        [StockID],[SKU]
    FROM [AlternateSKUs]
    )
SELECT
    Orders.[order-id],
    Stock.StockID,
    Stock.sku AS SKU, 
    Stock.ProductName AS PRODUCT,
    SUM(OrderItems.[quantity-purchased]) as Qty

FROM 
    Orders
JOIN OrderItems
    ON Orders.[order-id] = OrderItems.[order-id]
JOIN StockSKUs
    ON OrderItems.[SKU] = StockSKUs.[SKU]
JOIN CMRC_Stock as Stock 
    ON StockSKUs.[StockID] = Stock.[StockID]
WHERE
    Orders.[status] = 'PRINTED'
    AND Orders.channelId != 21

GROUP BY Orders.[order-id], Stock.StockID, Stock.SKU, Stock.ProductName

ORDER BY Qty DESC, Stock.SKU

随后会出现一个 SQL Fiddle。

【讨论】:

  • 成功了。非常感谢,感谢您的解释。我今天学到了一些新东西。甚至不知道 WITH 语句。
猜你喜欢
  • 2020-11-06
  • 2015-02-02
  • 2021-07-25
  • 2011-09-27
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多