2014-02-13 141 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会有所帮助。