如何加快此SQL查询?

时间:2010-08-21 06:44:09

标签: sql-server

我在SQL中使用了以下表格函数:

USE [EEMSPROD]
GO
/****** Object: UserDefinedFunction [dbo].[OpenTRF] Script Date: 08/21/2010 11:06:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER function [dbo].[OpenTRF]() RETURNS @TblOpenTRF TABLE ([Req No] NVARCHAR(50),[Travel from Date] datetime,[Travel to Date] datetime,[Employee ID] varchar(50),[Employee Name] varchar(50),
Designation varchar(50),[Travel Purpose] varchar(50), Approver varchar(50),[Booking Type] varchar(50), [Amount Payable to TA] float, [Total Estimated Approved Amount] float,
[Est Travel Cost] float,[Est L and B] float,[Est Incidental Cost] float, Zone varchar(50), Location varchar(50), Department varchar(50), Status varchar(50), [Cost Center] varchar(50) collate database_default)
as
begin
declare @ActNo int
declare @BookId varchar(50)
declare @maxDate datetime
declare @minDate datetime
declare @CurrDate datetime
declare @TVBDate datetime
declare @PassName varchar(50)
declare @PassCName varchar(50)
declare @Desig varchar(50)
declare @TVLPurpose varchar(50)
declare @Approver varchar(50)
declare @BookType varchar(50)
declare @AmtPayable float
declare @TotEstAmt float
declare @EstTvlCost float
declare @EstLanB float
declare @EstIncCost float
declare @Zone varchar(50)
declare @Location varchar(50)
declare @Depart varchar(50)
declare @CostCenter varchar(50)
declare @AirCost float
declare @TrainCost float
declare @HotelCost float
declare @Status varchar(50)

set @CurrDate=getdate()
DECLARE FrmTicket CURSOR FOR select Book_Id,Activity_no,TVB_Date,Pass_Name,Pass_Contac t_Name,Purpose,Approver_Contact_Name,Book_Type,Dep artment,Cost_Center,isnull(Incidental_Cost,0),Stat us from [TATA_TRAVEL_TICKETINFO] where Status in ('Submitted','Approved','Invoiced','Booked') and Book_Id not in (select Book_Id from Tata_Travel_ExpenseInfoNew)
OPEN FrmTicket
FETCH NEXT FROM FrmTicket INTO @BookId,@ActNo,@TVBDate,@PassName,@PassCName,@TVLP urpose,@Approver,@BookType,@Depart,@CostCenter,@Es tIncCost,@Status
WHILE @@FETCH_STATUS = 0 Begin
select @Desig=Designation,@Zone=Zone_Name,@Location=Locat ion_Name from [TATA_Master_EmployeeMaster] where Emp_Code=@PassName
select @AirCost=sum(isnull(Act_Cost,0)) from [TATA_TRAVEL_AirwayDetails] where Temp_Activity_No=@ActNo
select @TrainCost=sum(isnull(Act_Cost,0)) from [TATA_TRAVEL_TrainDetails] where Temp_Activity_No=@ActNo
select @HotelCost=sum(isnull(Act_Cost,0)) from [TATA_TRAVEL_HotelDetails] where Temp_Activity_No=@ActNo
select @minDate=min(convert(datetime,tdate,105)),@maxDate =max(convert(datetime,tdate,105)) from [TATA_TRAVEL_TRAVELPLAN] where Temp_Activity_No=@ActNo and Trip_Status!='Cancelled'
set @TVBDate=@maxDate
if(@maxDate < @CurrDate)
begin
set @AmtPayable=isnull(@AirCost,0)+isnull(@TrainCost,0 )
select @EstTvlCost=sum(isnull(Est_cost,0)) from [TATA_TRAVEL_TRAVELPLAN] where temp_activity_no=@ActNo
select @EstLanB=sum(isnull(Estimated_cost,0)) from [TATA_TRAVEL_BoardingPlan] where temp_activity_no=@ActNo
set @TotEstAmt=isnull(@EstTvlCost,0)+isnull(@EstLanB,0 )+isnull(@EstIncCost,0)
set @EstLanB=isnull(@EstLanB,0)
INSERT INTO @TblOpenTRF ([Req No],[Travel from Date],[Travel to Date],[Employee ID],[Employee Name],Designation,[Travel Purpose],Approver,[Booking Type],[Amount Payable to TA],
[Total Estimated Approved Amount],[Est Travel Cost],[Est L and B],[Est Incidental Cost],Zone,Location,Department,[Cost Center],Status)
VALUES(@BookId,@minDate,@TVBDate,@PassName,@PassCN ame,@Desig,@TVLPurpose,@Approver,@BookType,@AmtPay able,@TotEstAmt,@EstTvlCost,@EstLanB,@EstIncCost,
@Zone,@Location,@Depart,@CostCenter,@Status)
End
FETCH NEXT FROM FrmTicket INTO @BookId,@ActNo,@TVBDate,@PassName,@PassCName,@TVLP urpose,@Approver,@BookType,@Depart,@CostCenter,@Es tIncCost,@Status
END
CLOSE FrmTicket
DEALLOCATE FrmTicket
return
end;

创建此表内联函数后,我创建了视图以从@tblOpentrf获取数据,如下所示:

ALTER VIEW [dbo].[OpenTRFView]
AS
SELECT [Req No], [Employee ID], [Employee Name], Designation, [Travel Purpose], Approver, [Booking Type], [Amount Payable to TA],
[Total Estimated Approved Amount], [Est Travel Cost], [Est L and B], [Est Incidental Cost], Zone, Location, Department, Status, [Cost Center],
[Travel from Date], [Travel to Date]
FROM dbo.OpenTRF() AS OpenTRF_1

之后我使用了以下查询在前端显示:

Select OpenTRFView.[Req No][Req No],OpenTRFView.[Travel from Date][Travel from Date],OpenTRFView.[Travel to Date][Travel to Date],OpenTRFView.[Employee ID][Employee ID],OpenTRFView.[Employee Name][Employee Name],OpenTRFView.[Designation][Designation],OpenTRFView.[Travel Purpose][Travel Purpose],OpenTRFView.[Approver][Approver],OpenTRFView.[Booking Type][Booking Type],OpenTRFView.[Amount Payable to TA][Amount Payable to TA],OpenTRFView.[Total Estimated Approved Amount][Total Estimated Approved Amount],OpenTRFView.[Est Travel Cost][Est Travel Cost],OpenTRFView.[Est L and B][Est L and B],OpenTRFView.[Est Incidental Cost][Est Incidental Cost],OpenTRFView.[Zone][Zone],OpenTRFView.[Location][Location],OpenTRFView.[Department][Department],OpenTRFView.[Cost Center][Cost Center],OpenTRFView.[Status][Status] from OpenTRFView

我的问题是,如果有大量记录,查询需要花费大量时间来执行。这需要大约一个小时,我需要将其减少到10或15秒。

有没有人有任何想法?

2 个答案:

答案 0 :(得分:4)

我将把你的问题投票为一个很好的例子,说明如何不在SQL Server中编写好的代码。

这是关系数据库中问题的经典程序解决方案,显然可以通过关系数据库很好地解决这个问题:声明性的基于集合的编程。

你正在做的是加载到一个表变量中,通过痛苦行加入行,并为每行执行多个查询以获取更多信息。

通过消除游标和使用连接,这很容易简化 - 甚至相关的子查询可能比游标中的多个语句快得多。此外,对于某些您正在进行修改的内容,可能会有一个索引视图,这会使这些子查询更快。

基本上:

SELECT columns_you_need
FROM [TATA_TRAVEL_TICKETINFO] AS t1
INNER JOIN [TATA_Master_EmployeeMaster] AS t2
    ON t2.Emp_Code = t1.Pass_Name

因为您的TVF是参数化的,如果您无法将整个视图转换为一个视图,那么可以将其转换为内联表值函数 - 内联TVF相当于视图的性能,优化器可以推送周围的事情更容易。

因此,除了您正在使用的这种性能不佳的程序技术之外,多语句TVF通常不会表现得特别好,因为它是优化器的黑盒子。

如果您提供完整的脚本来创建和填充表格以及示例结果,我会在此将其转换为基于集合的解决方案,但如果不这样做,尝试提供更详细的信息会非常耗费时间溶液

答案 1 :(得分:2)

你的问题,最可能,应该在你的功能中!

视图SEEM中的视图和查询是直截了当的。

可能导致缓慢的一些常见可能原因: -

  1. 使用CURSOR
  2. 带有IN子句的子查
  3. 带有NOT IN子句的子查询中的子查
  4. 以上所有这些都可能会使查询执行变慢。 但是,这只是基于查询您的查询。 这是QUERY EXECUTION计划,它将真正为您提供有关可能导致缓慢的信息!!

    诸如索引,统计数据更新,桌面大小以及各种其他因素之类的东西可能会导致您的问题