如何使光标更快

Ham*_*han -2 sql t-sql sql-server-2005 cursor duplicate-removal

我已将此光标写入佣金报告.会发生什么是佣金来自一个表,记录是另一个表.我根据某些标准匹配两个(没有完全匹配).问题是存在记录的重复.当我将佣金与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 
Run Code Online (Sandbox Code Playgroud)

我已经阅读了如何更快地制作T-SQL游标的答案为此,我得到的是以表格形式重写此查询.但我确实有另一个使用连接的查询,并且快速闪电.问题是,它无法区分我records表中的重复项.

有什么我可以做的更快.这是首要问题.如果没有,你有没有其他方法可以做到这一点.

我特别需要帮助

  • 将使用视图或存储过程帮助
  • 我有一种方法可以在Cursor中使用缓存来加快速度
  • 语法中的任何其他选项

Aar*_*and 8

第一个选项是为光标设置资源最少的选项:

declare commission_cursor cursor
local static read_only forward_only
for 
Run Code Online (Sandbox Code Playgroud)

接下来是调查是否需要光标.在这种情况下,我认为你可以通过一次传递和没有循环来做同样的事情:

;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;
Run Code Online (Sandbox Code Playgroud)

如果这仍然很慢,那么游标可能不是问题 - 下一步将调查可以实现哪些索引以使此查询更有效.