使用 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/
以下是我的查询,执行需要将近 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/