使用 While 循环减少查询的执行时间

Reducing execution time of query with While loop

以下是我的查询,执行需要将近 31 分钟,导致超时 exception.is 有任何方法可以减少我的执行时间。 我试过的 我试图更改执行路径并从 select statement.still 中删除不需要的列,但没有任何效果。 这是我的查询

Alter Procedure [dbo].[sp_Report_Customer_Due_List_TimeOut]
    @AreaCode int = Null,
    @CustomerGroupId int = Null
As
Begin

 Declare @AreaCode_Timeout int=Null
 Declare @CustomerGroupId_Timeout int=Null

 Set @AreaCode_Timeout = @AreaCode
 Set @CustomerGroupId_Timeout = @CustomerGroupId

Declare @SourceTable Table
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Customer_ID] [int],
    [Customer_Name] [varchar](100),
    [Address] [varchar](200),
    [Address1] [varchar](200),
    [Address2] [varchar](200),
    [Phone_Office] [varchar](50),
    [Phone_Mobile] [varchar](50),
    [Receipt_No] [int],
    [Transaction_Date] [datetime],
    [Debit] [decimal](18, 2),
    [Credit] [decimal](18, 2),
    [Sales_Master_ID] [int]
)

Insert Into @SourceTable 
    ([Customer_ID],[Customer_Name],[Address],[Address1],[Address2],
    [Phone_Office],[Phone_Mobile],[Receipt_No],[Transaction_Date]
    ,[Debit],[Credit]
    ,[Sales_Master_ID])

Select C.[Customer_ID]
  ,[Customer_Name]
  ,[Address]
  ,[Address1]
  ,[Address2]
  ,[Phone_Office]
  ,[Phone_Mobile]
  ,ISNULL([Receipt_No], 0) As Receipt_No
  ,[Transaction_Date]
  ,ISNULL([Debit], 0) As Debit
  ,ISNULL([Credit], 0) As Credit
  ,[Sales_Master_ID]
From [Acc_Customer] AC
Left Outer Join [Customer] C On AC.[Customer_ID] = C.[Customer_ID]
Where (@AreaCode_Timeout Is Null Or [Area_Code] = @AreaCode_Timeout) And
      (@CustomerGroupId_Timeout Is Null Or [Customer_Group_ID] = @CustomerGroupId_Timeout)  
Order By AC.[Customer_ID], [Transaction_Date]

Declare @AmountPaid decimal(18,2)
Declare @Debit decimal(18,2)
Declare @CurrentCustomerId int
Declare @PreviousCustomerId int 
Set @PreviousCustomerId= 0
Declare @ObDebit decimal(18,2)
Declare @ObCredit decimal(18,2)
Declare @RowCount int

Set @RowCount = (Select COUNT(Customer_ID) From @SourceTable)
Declare @Count int
Set @Count = 1

While @Count <= @RowCount
Begin
    Set @CurrentCustomerId = (Select Customer_ID From @SourceTable Where Id = @Count)

    If @CurrentCustomerId <> @PreviousCustomerId
    Begin

        Set @PreviousCustomerId = (Select @CurrentCustomerId)
        Set @AmountPaid = (Select SUM(ISNULL(Credit,0)) From @SourceTable Where Customer_ID = @CurrentCustomerId)
        Set @ObDebit=(Select  SUM(ISNULL(OB_Debit,0)) From Customer Where  Customer_ID = @CurrentCustomerId)
        Set @ObCredit=(Select  SUM(ISNULL(OB_Credit,0)) From Customer Where  Customer_ID = @CurrentCustomerId)
        Set @Debit = (Select ISNULL(Debit,0) From @SourceTable Where Id = @Count)
        Set @Debit= @Debit + (@ObDebit - @ObCredit)

        Update @SourceTable
            Set Debit = @Debit
        Where
            Id = @Count
    End

    If @AmountPaid > 0
    Begin
        Set @Debit = (Select ISNULL(Debit,0) From @SourceTable Where Id = @Count)

        If @Debit >= @AmountPaid
        Begin
            Set @Debit = @Debit - @AmountPaid
            Set @AmountPaid = 0
        End
        Else
        Begin
            Set @AmountPaid = @AmountPaid - @Debit
            Set @Debit = 0

        End

        Update @SourceTable
            Set Debit = @Debit
        Where
            Id = @Count
    End
    Set @Count = @Count + 1

End


Select 
    ST.[Customer_ID],ST.[Customer_Name],ST.[Address],ST.[Address1],ST.[Address2],ST.[Phone_Office],ST.[Phone_Mobile]
    ,ST.[Receipt_No],ST.[Transaction_Date],ST.[Sales_Master_ID]
    ,SM.[Counter_Name],SM.[Form_Type],SM.[Invoice_No],ISNULL(ST.[Debit],0) As 'Due_Amount',ISNULL(T2.Out_Standing_Amount,0) As Out_Standing_Amount
    ,C.[Credit_Duration],(DATEDIFF(day, ST.Transaction_Date, GETDATE())) As 'Due_Days'

From @SourceTable ST

Left Join Customer C On ST.Customer_ID = C.Customer_ID
Left Join Sales_Master SM On ST.Sales_Master_ID = SM.Serial_No
Left Join (Select Acc_Customer.Customer_ID, ((OB_Debit + SUM(ISNULL(Debit,0))) - (OB_Credit + SUM(ISNULL(Credit,0)))) As 'Out_Standing_Amount' From Acc_Customer 
Left Join Customer On Acc_Customer.Customer_ID = Customer.Customer_ID

Group By Acc_Customer.Customer_ID, OB_Debit, OB_Credit) T2 
On ST.Customer_ID = T2.Customer_ID

Where DATEDIFF(day, Transaction_Date, GETDATE()) >= C.Credit_Duration
And Out_Standing_Amount <> 0
And ST.[Debit] <> 0

order by [Customer_Name]

End

当我删除程序名称并在新查询中执行他的查询时 window 只用了 1 second.why 是这样吗?

尝试不使用循环的查询,如下所示:

UPDATE ST
SET Debit = CASE 
                WHEN AmountPaid > 0 THEN 
                    CASE 
                        WHEN Debit >= AmountPaid THEN  Debit + (ObDebit - ObCredit) - AmountPaid
                        ELSE 0
                    END
                ELSE Debit + (ObDebit - ObCredit)
            END
FROM @SourceTable   ST
OUTER APPLY (
    SELECT
        AmountPaid  = SUM(ISNULL(Credit,0))
    FROM @SourceTable   S
    WHERE S.Customer_ID = ST.Customer_ID
) P
OUTER APPLY (
    SELECT
        ObDebit     = SUM(ISNULL(OB_Debit,0)),
        ObCredit    = SUM(ISNULL(OB_Credit,0))
    FROM Customer C
    WHERE C.Customer_ID = ST.Customer_ID
) C 

P.S。而不是 @Count 变量你应该使用游标: https://www.mssqltips.com/sqlservertip/1599/sql-server-cursor-example/