带有连接子查询优化的SQL查询

时间:2018-02-21 21:42:18

标签: sql sql-server query-optimization

以下声明用于收集产品在各个杂货店销售情况的数字。基本上,它是执行4次相同的语句,区别在于检查哪个存储,然后加入。单独地,每个语句不超过5秒,但加入时,最多可能需要2分钟。我试过移动和切换ON条款,以及WHERE条款,并且没有运气。我知道原因是每个查询必须先处理才能加入,然后缩小,但即便如此,我认为它只会加起来大约20秒,而不是120!

该语句由另一个脚本生成,并根据用户输入进行更改。此示例在1分30秒时返回230行。

SELECT store1.upc,store1.description,store1.size,store1.uom,store1.price,
        store_qty, store_weight, store_sales,
        O_qty, O_weight, O_sales,
        W_qty, W_weight, W_sales,
        S_qty, S_weight, S_sales
FROM
(
    SELECT itemdetail.upc, itemdetail.description, itemdetail.size, itemdetail.uom, itemdetail.price,
            sum(store.quantity) AS store_qty,
            sum(store.weight) AS store_weight,
            sum(store.sales) AS store_sales
    FROM movementweekly AS store
        LEFT JOIN itemdetail ON itemdetail.upc = store.upc 
    WHERE store.date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00'
        AND ((itemdetail.upc >= 5100000000 AND itemdetail.upc <= 5100099999) OR (itemdetail.upc >= 51000000000 AND itemdetail.upc <= 51000999999) OR (itemdetail.upc >= 510000000000 AND itemdetail.upc <= 510009999999))
    GROUP BY itemdetail.upc,itemdetail.description,itemdetail.size,itemdetail.uom,itemdetail.price
) AS store1
    LEFT JOIN
    (
        SELECT O.upc, sum(O.quantity) AS O_qty, sum(O.weight) AS O_weight, sum(O.sales) AS O_sales 
        FROM movementweekly AS O
        LEFT JOIN itemdetail ON itemdetail.upc = O.upc 
        WHERE O.store = 1
            AND date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00' 
            AND ((itemdetail.upc >= 5100000000 AND itemdetail.upc <= 5100099999) OR (itemdetail.upc >= 51000000000 AND itemdetail.upc <= 51000999999) OR (itemdetail.upc >= 510000000000 AND itemdetail.upc <= 510009999999))
        GROUP BY O.upc
    ) AS O1 ON store1.upc = O1.upc  
    LEFT JOIN
    (
        SELECT W.upc, sum(W.quantity) AS W_qty, sum(W.weight) AS W_weight, sum(W.sales) AS W_sales 
        FROM movementdaily AS W
        LEFT JOIN itemdetail ON itemdetail.upc = W.upc 
        WHERE W.store = 2
            AND date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00' 
            AND ((itemdetail.upc >= 5100000000 AND itemdetail.upc <= 5100099999) OR (itemdetail.upc >= 51000000000 AND itemdetail.upc <= 51000999999) OR (itemdetail.upc >= 510000000000 AND itemdetail.upc <= 510009999999))
        GROUP BY W.upc
    ) AS W1 ON store1.upc = W1.upc
    LEFT JOIN
    (
        SELECT S.upc, sum(S.quantity) AS S_qty, sum(S.weight) AS S_weight, sum(S.sales) AS S_sales 
        FROM movementdaily AS S
            LEFT JOIN itemdetail ON itemdetail.upc = S.upc 
        WHERE S.store = 3
            AND date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00' 
            AND ((itemdetail.upc >= 5100000000 AND itemdetail.upc <= 5100099999) OR (itemdetail.upc >= 51000000000 AND itemdetail.upc <= 51000999999) OR (itemdetail.upc >= 510000000000 AND itemdetail.upc <= 510009999999))
        GROUP BY S.upc
    ) AS S1 ON store1.upc = S1.upc
ORDER BY store_sales DESC

这是前五行,作为一个例子。 忽略重量列全为零。它用于从同一模板生成的其他语句。

|UPC     |  |Description                 |  |size | |uom  | |Price| |Store_qty| |Store_weight|  |Store_sales|   |O_qty| |O_weight|  |O_Sales|   |W_qty| |W_weight|  |W_Sales|   |S_qty| |S_weight|  |S_Sales|
5100013279  Swanson Chicken Broth Red Sod   32      oz      2.99    614         0               1676.47         207     0           580.32      218     0           622.12      189     0           474.03
5100012114  Swanson Broth Chicken           32      oz      2.99    597         0               1616.73         148     0           414.8       201     0           565.35      248     0           636.58
5100018806  Swanson Chunk White Chicken     12.5    oz      3.49    382         0               1524.18         91      0           363.09      147     0           586.53      144     0           574.56
5100000011  Campbells Tomato Soup           10.75   oz      0.99    1499        0               1432.71         624     0           590.59      490     0           475.41      387     0           368.69
5100000803  V8 Vegetable Juice              46      oz      3.39    454         0               1400.11         200     0           602.24      192     0           594.80      62      0           203.06

1 个答案:

答案 0 :(得分:0)

尝试以下

-- you can select all the necessary items into temporary table
SELECT upc, description, size, uom, price
INTO #temp_itemdetail
FROM itemdetail
WHERE ((upc >= 5100000000 AND upc <= 5100099999) OR (upc >= 51000000000 AND upc <= 51000999999) OR (upc >= 510000000000 AND upc <= 510009999999))

-- add primary key into temp table
ALTER TABLE #temp_itemdetail ADD PRIMARY KEY(upc)

-- and you can use two subqueries instead four
SELECT
  q1.upc,q1.description,q1.size,q1.uom,q1.price,
  q1.store_qty, q1.store_weight, q1.store_sales,
  q1.O_qty, q1.O_weight, q1.O_sales,
  q2.W_qty, q2.W_weight, q2.W_sales,
  q2.S_qty, q2.S_weight, q2.S_sales
FROM
  (
    SELECT
      i.upc, i.description, i.size, i.uom, i.price,

      sum(s.quantity) AS store_qty,
      sum(s.weight) AS store_weight,
      sum(s.sales) AS store_sales,

      sum(CASE WHEN s.store=1 THEN s.quantity END) AS O_qty,
      sum(CASE WHEN s.store=1 THEN s.weight END) AS O_weight,
      sum(CASE WHEN s.store=1 THEN s.sales END) AS O_sales
    FROM movementweekly s
    JOIN #temp_itemdetail i ON i.upc = s.upc 
    WHERE s.date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00'
      --AND ((i.upc >= 5100000000 AND i.upc <= 5100099999) OR (i.upc >= 51000000000 AND i.upc <= 51000999999) OR (i.upc >= 510000000000 AND i.upc <= 510009999999))
    GROUP BY i.upc,i.description,i.size,i.uom,i.price
  ) AS q1
LEFT JOIN
  (
    SELECT
      s.upc,

      sum(CASE WHEN s.store=2 THEN s.quantity END) AS W_qty,
      sum(CASE WHEN s.store=2 THEN s.weight END) AS W_weight,
      sum(CASE WHEN s.store=2 THEN s.sales END) AS W_sales,

      sum(CASE WHEN s.store=3 THEN s.quantity END) AS S_qty,
      sum(CASE WHEN s.store=3 THEN s.weight END) AS S_weight,
      sum(CASE WHEN s.store=3 THEN s.sales END) AS S_sales
    FROM movementdaily s
    JOIN #temp_itemdetail i ON i.upc = s.upc 
    WHERE s.store IN(2,3)
      AND date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00' 
      --AND ((i.upc >= 5100000000 AND i.upc <= 5100099999) OR (i.upc >= 51000000000 AND i.upc <= 51000999999) OR (i.upc >= 510000000000 AND i.upc <= 510009999999))
    GROUP BY s.upc
  ) AS q2 ON q1.upc = q2.upc

ORDER BY q1.store_sales DESC

-- drop temp table
DROP TABLE #temp_itemdetail

如果表格movementweekly包含所有必要信息,您可以使用单个查询

SELECT
  i.upc, i.description, i.size, i.uom, i.price,

  sum(s.quantity) AS store_qty,
  sum(s.weight) AS store_weight,
  sum(s.sales) AS store_sales,

  sum(CASE WHEN s.store=1 THEN s.quantity END) AS O_qty,
  sum(CASE WHEN s.store=1 THEN s.weight END) AS O_weight,
  sum(CASE WHEN s.store=1 THEN s.sales END) AS O_sales,

  sum(CASE WHEN s.store=2 THEN s.quantity END) AS W_qty,
  sum(CASE WHEN s.store=2 THEN s.weight END) AS W_weight,
  sum(CASE WHEN s.store=2 THEN s.sales END) AS W_sales,

  sum(CASE WHEN s.store=3 THEN s.quantity END) AS S_qty,
  sum(CASE WHEN s.store=3 THEN s.weight END) AS S_weight,
  sum(CASE WHEN s.store=3 THEN s.sales END) AS S_sales
FROM movementweekly s
JOIN #temp_itemdetail i ON i.upc = s.upc 
WHERE s.date BETWEEN '2017-01-09 00:00:00' AND '2017-04-09 00:00:00'
GROUP BY i.upc,i.description,i.size,i.uom,i.price
ORDER BY store_sales DESC