2012-04-02 207 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