查询调优SQL Server 2008

时间:2011-04-06 11:35:39

标签: sql sql-server sql-server-2008

我有一个名字“vw_AllJobsWithRecruiter”。

ALTER VIEW dbo.vw_AllJobsWithRecruiter
AS
SELECT TOP(SELECT COUNT(iJobID_PK) FROM dbo.tbUS_Jobs)
         iJobId_PK AS JobId,
         dbo.ufn_JobStatus(iJobId_PK) AS JobStatus,
         dbo.ufn_RecruiterCompanyName(iJobId_PK) AS CompanyName,
         sOther AS OtherCompanyName
FROM dbo.tbUS_Jobs
WHERE bDraft = 0
ORDER BY dtPostedDate DESC

此视图仅包含3278行。

如果我执行以下查询:

SELECT * FROM vw_AllJobsWithRecruiter
WHERE  OtherCompanyName LIKE '%Microsoft INC%'

执行时间不到一秒。

现在我的问题是:

如果我使用以下查询查询:

SELECT * FROM vw_AllJobsWithRecruiter
WHERE CompanyName LIKE '%Microsoft INC%' 
      OR OtherCompanyName LIKE '%Microsoft INC%'

执行需要30秒,从前端开始抛出超时错误。 功能在这里:

CREATE Function [dbo].[ufn_RecruiterCompanyName] (@JobId bigint)      
RETURNS nvarchar(200)      
AS      
BEGIN      
 DECLARE @ResultVar nvarchar(200)     
 DECLARE @RecruiterId bigint     

 select @RecruiterId = iRecruiterId_FK from dbo.tbUS_Jobs     with (Nolock)   
 where iJobId_PK = @JobId;      

 Select @ResultVar = sCompanyName from dbo.tbUS_RecruiterCompanyInfo     with (Nolock)   
 where iRecruiterId_FK = dbo.ufn_GetParentRecruiterID(@RecruiterId)      

 return isnull(@ResultVar,'')      

END 

另一个功能

CREATE Function [dbo].[ufn_GetParentRecruiterID](@RecruiterId bigint)  
returns bigint  
as  
begin   
declare @ParentRecruiterId bigint  

SELECT @ParentRecruiterId = iParentId FROM dbo.tbUS_Recruiter with (Nolock)   
WHERE iRecruiterId_PK = @RecruiterId  

IF(@ParentRecruiterId = 0)  
 SET @ParentRecruiterId = @RecruiterId  

RETURN @ParentRecruiterId  
end 

我的问题是

  
      
  1. 为什么要花这么多时间来执行?
  2.   
  3. 如何缩短执行时间?
  4.   

非常感谢您的关注。

2 个答案:

答案 0 :(得分:4)

第一个查询仅对返回的行调用dbo.ufn_RecruiterCompanyName(),它会对存储的值进行过滤。对于第二个Query,SQL Server需要为所有行调用ufn。根据功能,这可能会导致延迟。

在查询分析器中检查这一点,并尝试避免第二个查询^^

在查看自定义函数后,我建议使用连接表重写View。在这些函数中执行查找时,SQL Server会为它接触或传递的每一行调用它们。使用LEFT JOIN允许服务器更快地使用索引和密钥,并且应该在不到一秒的时间内提供数据。

如果没有所有自定义函数和所有表的定义,我不能给你一个新视图的示例,但它应该看起来像这样:

SELECT
    jobs.Jobid,
    jobstatus.Jobstatus,
    recruiter.Company
FROM jobs
LEFT JOIN jobstatus ON jobs.Jobid = jobstatus.Jobid
LEFT JOIN recruiter ON jobs.Recruiterid = recruiter.Recruiterid

答案 1 :(得分:1)

问题是你的嵌套函数调用。

您正在ufn_RecruiterCompanyName条款中调用WHERE,虽然是间接的。

这意味着,您的WHERE子句不是Sargable,并且必须为每一行运行该功能。

该函数也调用ufn_GetParentRecruiterID。由于这是在第一个函数中的WHERE子句中,也是非Sargable,因此您基本上在表中每行进行两次表扫描。

JOIN替换函数调用,您将看到性能的巨大提升。