2014-02-13 137 views
0

這是我必須優化的代碼,我設法將它只用索引的一半開始代價並更改SUBSTRING語句的LIKE。我現在的問題是最後一行的子查詢和select中的SUM行,我相信我必須通過創建一個新的表或列來擺脫這些問題,但無法完成。查詢優化,(子查詢)(sql-transact)

SELECT 
C.LastName as Customer , e.LastName as SalesPerson, s.ProductID, 
p.Name as ProductName, SUM(s.Quantity) as quantity, 
SUM (p.Price * s.Quantity) as amount 
FROM dbo.Sales s, dbo.Customers c, dbo.Employees e, dbo.Products p 
WHERE 
s.CustomerID = c.CustomerID and 
s.ProductID = p.ProductID and 
s.SalesPersonID = e.EmployeeID and 
p.Name like 'Paint%' 
GROUP BY C.LastName , e.LastName , s.ProductID, p.Name 
HAVING sum (s.Quantity) < 
(select AVG(s2.Quantity) from dbo.Sales s2 where s2.ProductID=s.ProductID) 

任何幫助,歡迎提前致謝。

+1

你有使用EXPLAIN看到優化計劃?不幸的是,HAVING sum()可能會迫使你閱讀很多行。數據是否重新設計了一個選項?是否有可能確保這個查詢只運行很少(比如用cron作業)並且緩存在文本文件或sales_volume表格的某處? –

+0

你使用什麼數據庫? –

+0

@TomHaws你的意思是執行?是的,我做了,就像你說的那樣,HAVING和子查詢給我70%的估計成本。允許重新設計。 這是SQL Server。 –

回答

0

現在不能測試,但我認爲這應該工作:

SELECT c.LastName as Customer , 
     e.LastName as SalesPerson, 
     s.ProductID, 
     p.Name as ProductName, 
     SUM(s.Quantity) as quantity, 
     SUM(p.Price * s.Quantity) as amount 
    FROM dbo.Sales s, 
    JOIN dbo.Customers c 
    ON c.CustomerID = s.CustomerID 
    JOIN dbo.Employees e 
    ON e.EmployeeID = s.SalesPersonID 
    JOIN dbo.Products p 
    ON p.ProductID = s.ProductID 
    AND p.Name like 'Paint%' 
    JOIN (SELECT ProductID, 
       AVG(Quantity) as avg_Quantity 
      FROM dbo.Sales) s2 
    ON s2.ProductID = s.ProductID 
GROUP BY c.LastName , e.LastName , s.ProductID, p.Name 
HAVING sum(s.Quantity) < AVG(s2.avg_Quantity) 
+0

事實上,我認爲你可以用Min(s2.avg_Quantity)替換AVG(s2.avg_Quantity);效果應該是相同的,但我猜Min()會比AVG()快(一小部分)。 (沒有測試過,只是大聲思考,但我猜想實現AVG()需要更多的邏輯) – deroby

0

如果使用SQL Server,你可以簡化這個有點用窗函數:

WITH cte AS ( SELECT C.LastName AS Customer 
         , e.LastName AS SalesPerson 
         , s.ProductID 
         , p.Name AS ProductName 
         , SUM(s.Quantity) AS quantity 
         , SUM(p.Price * s.Quantity) AS amount 
         , SUM(SUM(s.Quantity)) OVER (PARTITION BY s.ProductID)*1.0/SUM(COUNT(*)) OVER (PARTITION BY s.ProductID) AS Avg_Qty 
       FROM  dbo.Sales s 
        JOIN dbo.Customers c ON s.CustomerID = c.CustomerID 
        JOIN dbo.Employees e ON s.SalesPersonID = e.EmployeeID 
        JOIN dbo.Products p ON s.ProductID = p.ProductID 
       WHERE s.Name LIKE 'Paint%' 
       GROUP BY C.LastName 
         , e.LastName 
         , s.ProductID 
         , p.Name 
      ) 
SELECT * 
FROM cte 
WHERE quantity < Avg_Qty 

添加Name_Category場或類似避免使用LIKE會有所幫助。