Помогите заменить этот курсор SQL на лучший код - PullRequest
2 голосов
/ 16 апреля 2010

Может кто-нибудь помочь мне улучшить производительность этой логики курсора из SQL 2000. Она отлично работает в SQl2005 и SQL2008, но для запуска в SQL 2000 требуется не менее 20 минут. Кстати, я бы никогда не решил использовать курсор и я не писал этот код, просто пытался заставить его работать быстрее. Обновление этого клиента до 2005/2008 не вариант в ближайшем будущем.

-------------------------------------------------------------------------------
------- Rollup totals in the chart of accounts hierarchy
-------------------------------------------------------------------------------
DECLARE @B_SubTotalAccountID int, @B_Debits money, @B_Credits money, @B_YTDDebits money, @B_YTDCredits money

DECLARE Bal CURSOR FAST_FORWARD FOR 
 SELECT SubTotalAccountID, Debits, Credits, YTDDebits, YTDCredits FROM xxx 
  WHERE AccountType = 0 AND SubTotalAccountID Is Not Null and (abs(credits)+abs(debits)+abs(ytdcredits)+abs(ytddebits)<>0)
OPEN Bal

FETCH NEXT FROM Bal INTO @B_SubTotalAccountID, @B_Debits, @B_Credits, @B_YTDDebits, @B_YTDCredits

--For Each Active Account
WHILE @@FETCH_STATUS = 0
 BEGIN

 --Loop Until end of subtotal chain is reached
 WHILE @B_SubTotalAccountID Is Not Null
  BEGIN

  UPDATE xxx2
  SET Debits = Debits + @B_Debits,
   Credits = Credits + @B_Credits,
   YTDDebits = YTDDebits + @B_YTDDebits,
   YTDCredits = YTDCredits + @B_YTDCredits
  WHERE GLAccountID = @B_SubTotalAccountID

  SET @B_SubTotalAccountID = (SELECT SubTotalAccountID FROM xxx2 WHERE GLAccountID = @B_SubTotalAccountID)

  END

 FETCH NEXT FROM Bal INTO @B_SubTotalAccountID, @B_Debits, @B_Credits, @B_YTDDebits, @B_YTDCredits

 END

CLOSE Bal
DEALLOCATE Bal

Ответы [ 2 ]

3 голосов
/ 16 апреля 2010
Update xx2
Set Credits = Credits + X1.CreditTotal
    , Debits = Debits + X1.DebitTotal
    , YtdDebits = YtdDebits + X1.YtdDebitTotal
    , YtdCredits = YtdCredits + X1.YtdDebitTotal
From xx2 As X2
    Join    (
            Select SubTotalAccountID, Sum(Debits) As DebitTotal, Sum(Credits) As CreditTotal
                , Sum(YtdDebits) As YtdDebitTotal, Sum(YtdCredits) As YtdCreditTotal
            From xxx
            Where AccountType = 0 
                And SubTotalAccountID Is Not Null 
                And (
                    Credits <> 0
                    Or Debits <> 0
                    Or YtdCredits <> 0
                    Or YtdDebits <> 0
                    )
            Group By SubTotalAccountID
            ) As X1
        On X1.SubTotalAccountID = X2.GLAccountID

Без схемы я не мог бы сказать, будет ли таблица xxx возвращать несколько строк для данного SubTotalAccountId.Я предположил, что он мог бы, и сгруппировал значения по этому столбцу, чтобы я получил одну строку для SubTotalAccountId.

Я также заменил использование ABS в предложении WHERE просто проверками на ноль.Это должно быть значительно быстрее.

Этот оператор UPDATE должен полностью заменить ваш курсор.

1 голос
/ 16 апреля 2010

Пара предложений:

1 - используйте профилировщик, чтобы сказать, какая его часть работает медленно - вы можете получить длительность для каждого оператора

2 - выполнить начальный оператор выбора (объявление курсора) вне процедуры и проверить план запроса. Это работает быстро? Правильно ли используются индексы?

3 - то же самое с оператором обновления - проверьте план запроса и использование индекса

4 - оператор 'set' после обновления выглядит странно - похоже, он получает значение в @B_SubTotalAccountID, которое затем немедленно заменяется 'fetch next'

...