我已将此光标写入佣金报告。会发生什么是佣金来自一个表,记录是另一个表。我根据某些标准匹配两个(没有完全匹配)。问题是存在记录的重复。当我将佣金与records
表匹配时,可能会导致重复这些重复。因此,代表获得更多报酬。另一方面,委托表中也有重复,但这些都是有效的,因为它们简单意味着账户已经支付了2个月。
我写了这个查询,但运行需要5分钟。我在记录表中有50,000条记录,在佣金表中有100,000条记录。有什么方法可以改进这个光标吗?
/* just preparation of cursor, this is not time consuming */
CREATE TABLE #result
(
repid INT,
AccountNo VARCHAR(100),
supplier VARCHAR(15),
CompanyName VARCHAR(200),
StartDate DATETIME,
EndDate DATETIME,
Product VARCHAR(25),
commodity VARCHAR(25),
ContractEnd DATETIME,
EstUsage INT,
EnrollStatus VARCHAR(10),
EnrollDate DATETIME,
ActualEndDate DATETIME,
MeterStart DATETIME,
MeterEnd DATETIME,
ActualUsage INT
)
DECLARE @AccountNo VARCHAR(100)
DECLARE @supplier VARCHAR(10)
DECLARE @commodity VARCHAR(15)
DECLARE @meterstart DATETIME
DECLARE @meterEnd DATETIME
DECLARE @volume FLOAT
DECLARE @RepID INT
DECLARE @Month INT
DECLARE @Year INT
SET @repID = 80
SET @Month = 1
SET @year = 2012
/* the actual cursor */
DECLARE commission_cursor CURSOR FOR
SELECT AccountNo,
supplier,
commodity,
meterStart,
MeterEnd,
Volume
FROM commission
WHERE Datepart(m, PaymentDate) = @Month
AND Datepart(YYYY, PaymentDate) = @Year
OPEN commission_cursor
FETCH next FROM commission_cursor INTO @AccountNo, @supplier, @commodity, @MeterStart, @MeterEnd, @Volume;
WHILE @@fetch_status = 0
BEGIN
IF EXISTS (SELECT id
FROM Records
WHERE AccountNo = @AccountNo
AND supplier = @supplier
AND Commodity = @commodity
AND RepID = @repID)
INSERT INTO #result
SELECT TOP 1 RepID,
AccountNo,
Supplier,
CompanyName,
[Supplier Start Date],
[Supplier End Date],
Product,
Commodity,
[customer end date],
[Expected Usage],
EnrollStatus,
ActualStartDate,
ActualEndDate,
@meterstart,
@MeterEnd,
@volume
FROM Records
WHERE AccountNo = @AccountNo
AND supplier = @supplier
AND Commodity = @commodity
AND RepID = @repID
AND @MeterStart >= Dateadd(dd, -7, ActualStartDate)
AND @meterEnd <= Isnull(Dateadd(dd, 30, ActualEndDate), '2015-12-31')
FETCH next FROM commission_cursor INTO @AccountNo, @supplier, @commodity, @MeterStart, @MeterEnd, @Volume;
END
SELECT *
FROM #result
/* clean up */
CLOSE commission_cursor
DEALLOCATE commission_cursor
DROP TABLE #result
我已阅读How to make a T-SQL Cursor faster?的答案,因为我得到的是以表格形式重写此查询。但我确实有另一个使用连接的查询,并且快速闪电。问题是,它无法区分我records
表中的重复项。
我能做些什么才能做得更快。这是首要问题。如果没有,你有没有其他办法可以做到。
我特别需要帮助
答案 0 :(得分:8)
第一个选项是为光标设置资源最少的选项:
declare commission_cursor cursor
local static read_only forward_only
for
接下来是调查是否需要光标。在这种情况下,我认为你可以通过一次传递和没有循环来做同样的事情:
;WITH x AS
(
SELECT
rn = ROW_NUMBER() OVER (PARTITION BY r.AccountNo, r.Supplier, r.Commodity, r.RepID
ORDER BY r.ActualEndDate DESC),
r.RepID,
r.AccountNo,
r.Supplier,
r.CompanyName,
StartDate = r.[Supplier Start Date],
EndDate = r.[Supplier End Date],
r.Product,
r.Commodity,
ContractEnd = r.[customer end date],
EstUsage = r.[Expected Usage],
r.EnrollStatus,
EnrollDate = r.ActualStartDate,
r.ActualEndDate,
c.MeterStart,
c.MeterEnd,
ActualUsage = c.Volume
FROM dbo.commission AS c
INNER JOIN dbo.Records AS r
ON c.AccountNo = r.AccountNo
AND c.Supplier = r.Supplier
AND c.Commodity = r.Commodity
AND c.RepID = r.RepID
WHERE
c.PaymentDate >= DATEADD(MONTH, @Month-1, CONVERT(CHAR(4), @Year) + '0101')
AND c.PaymentDate < DATEADD(MONTH, 1, CONVERT(CHAR(4), @Year) + '0101')
AND r.RepID = @RepID
)
SELECT RepID, AccountNo, Supplier, CompanyName, StartDate, EndDate,
Product, Commodity, ContractEnd, EstUsage, EnrollStatus, EnrollDate,
ActualEndDate, MeterStart, MeterEnd, ActualUsage
FROM x
WHERE rn = 1 --ORDER BY something;
如果这仍然很慢,那么游标可能不是问题 - 下一步将调查可能实现哪些索引以使此查询更有效。
答案 1 :(得分:0)
临时表是你的朋友
我解决问题的方法,合并来自两个表的数据,以复杂的方式删除重复项,一切都非常快,就是使用临时表。这就是我所做的
创建一个#temp表,从两个表中获取合并数据。即使您不需要,也要确保在两个表中都包含ID字段。这有助于删除重复项。
现在您可以对此表进行所有类型的计算。从表B中删除重复项,只需删除重复的表B ID。从表A中删除重复项,只需删除重复的表A ID。这个问题有更复杂的问题,但至少这可能是解决问题的最佳方法,如果游标过于昂贵并且需要相当长的时间来计算,那么它可以大大加快。在我的情况下,它需要+5分钟。 #temp表查询大约5秒,其中有更多的计算。
在应用Aaron解决方案时,光标没有变得更快。第二个查询更快但它没有给我正确的答案,所以最后我使用临时表。这是我自己的答案。