我有四张桌子:
personId int ,PersonName nvarchar(20)
..)autoId int,PersonId int,districtId int
):在特定地区工作的每个销售人员SalesId int,pointOfSalesId int,districtId int,pointOfSalesName nvarchar(20)
,...)每个区都有很多pointOfSales'。SalesPersonId 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秒!
那么,如何优化此存储过程以在最短时间内执行?
答案 0 :(得分: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