2012-04-02 247 views
0

我有四个表:SQL Server存储过程

  1. 业务员personId int ,PersonName nvarchar(20) ..)
  2. personAndDistrictautoId int,PersonId int,districtId int):每一个销售的人在一个特定的地区工作(S)
  3. PointOfSalesSalesId int,pointOfSalesId int,districtId int,pointOfSalesName nvarchar(20),...)每个地区有很多pointOfSales'。
  4. DailySalesSalesPersonId int,SoldAmount float,PointOfSalesId int, salesDate date,..):每日销售数据。

为了节省每天的销售额为每一个销售人员,我需要先显示一个清单,他销售的所有点售出量的总和(如果有的话)每个。

因此,我们需要的是显示特定日期的特定销售人员的所有销售点销售总额。

我有存储过程:

ALTER PROCEDURE [dbo].[SP_PoinOfSales_GetDataForEntry] 
     @SalesPersonId int=null, @SalesDate date=null 
AS 
    SELECT DISTINCT 
     par.SalesPersonId, 
     pos.pointOfsalesID, 
     pos.pointOfSalesName, 
     ISNULL((SELECT SUM(SoldAmount) AS Expr1 
       FROM 
        dbo.DailySales AS ds 
       WHERE 
        (SalesDate = CONVERT(VARCHAR, @salesDate, 102)) 
        AND (SalesPersonId = par.SalesPersonId) 
        AND (PointOfsalesID = ps.PointOfsalesID)), 0) AS SoldAmount, 
    FROM 
     dbo.PointOfSales AS pos 
    INNER JOIN 
     dbo.PersonAndDistrict AS par ON pos.districtId = par.districtId 
    WHERE 
     (@SalesPersonId IS NULL 
     OR par.SalesPersonId = @SalesPersonId) 
    GROUP BY 
     pos.districtId, 
     pos.pointOfSalesName, 
     pos.PointOfsalesID, 
     par.SalesPersonId 
    ORDER BY 
     pos.PointOfsalesID, 
     pos.districtId 

只返回800条记录(销售点的),它会超过6秒!

那么,如何优化这个存储过程才能在最短时间内执行?

+1

'@SalesPersonId为空或par.SalesPersonId = @ SalesPersonId'将可能为案件次优,你*始终*传递一个特定的'SalesPersonId'(至少除非你是在2008年和使用' OPTION(RECOMPILE)')。表上的哪些索引以及执行计划是什么样的? – 2012-04-02 20:19:11

+0

@Martin Smith忘记了参数嗅探错误,这是一个讨厌的错误 – 2012-04-02 20:37:36

回答

1

以一般的方式,我发现JOIN中的内联视图比SELECT子句更好地执行。所以我会重写这种方式。

SELECT DISTINCT par.salespersonid, 
      pos.pointofsalesid, 
      pos.pointofsalesname, 
      Isnull(t.expr1, 0), 
      as soldamount 
FROM dbo.pointofsales AS pos 
     INNER JOIN dbo.personanddistrict AS par 
     ON pos.districtid = par.districtid 
     LEFT JOIN (SELECT SUM(soldamount) AS expr1, 
         pointofsalesid, 
         salespersonid 
        FROM dbo.dailysales AS ds 
        WHERE (salesdate = CONVERT(VARCHAR, @salesDate, 102)) 
        GROUP BY pointofsalesid, 
          salespersonid) t 
     ON t.salespersonid = par.salespersonid 
      AND t.pointofsalesid = pos.pointofsalesid 
WHERE (@SalesPersonId IS NULL 
      OR par.salespersonid = @SalesPersonId) 
GROUP BY pos.districtid, 
      pos.pointofsalesname, 
      pos.pointofsalesid, 
      par.salespersonid 
ORDER BY pos.pointofsalesid, 
      pos.districtid 

另一种选择是移动到下方的CTE但是这主要是一种风格的东西,除非内嵌视图中的SQL代码重复。

WITH t 
    AS (SELECT SUM(soldamount) AS expr1, 
       pointofsalesid, 
       salespersonid 
     FROM dbo.dailysales AS ds 
     WHERE (salesdate = CONVERT(VARCHAR, @salesDate, 102)) 
     GROUP BY pointofsalesid, 
        salespersonid) 
SELECT DISTINCT par.salespersonid, 
       pos.pointofsalesid, 
       pos.pointofsalesname, 
       Isnull(t.expr1, 0) AS soldamount, 
FROM dbo.pointofsales AS pos 
     INNER JOIN dbo.personanddistrict AS par 
     ON pos.districtid = par.districtid 
     LEFT JOIN t 
     ON t.salespersonid = par.salespersonid 
      AND t.pointofsalesid = pos.pointofsalesid 
WHERE (@SalesPersonId IS NULL 
      OR par.salespersonid = @SalesPersonId) 
GROUP BY pos.districtid, 
      pos.pointofsalesname, 
      pos.pointofsalesid, 
      par.salespersonid 
ORDER BY pos.pointofsalesid, 
      pos.districtid 
+0

第一个选项不会解析我认为是因为GROUP错误 - expr1不在GROUP BY中。 'ORDER BY'也会失败,因为'districtid'不在选择列表中。但是,ORDER BY问题存在于OP的代码中。 – JNK 2012-04-02 20:22:46

+0

@JNK doh。谢谢,如果我不使用Instant SQL Formatter,我总是会删除GROUP BY子句。我也搞砸了一些逗号和parens。但是你可以通过一些不在选择中的东西来订购,只要它在群组中。 [我不确定我自己,所以我测试了它](http://data.stackexchange.com/stackoverflow/query/65732/order-by-and-group-by-but-not-in-select) – 2012-04-02 20:35:17

+0

@conrad ..谢谢,我选择了第一个选项进行了一些修改,再加上(@JNK提到的分组和orderby), – Salahaldin 2012-04-02 21:08:13