2011-04-06 133 views
3

我有一個視圖名稱「vw_AllJobsWithRecruiter」。查詢優化SQL Server 2008

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. 我該如何縮短執行時間?

非常感謝您的關注。

+0

子句TOP的用途是什麼(SELECT COUNT(iJobID_PK)FROM dbo.tbUS_Jobs)?這很奇怪,可能無用。如果你需要有iJobID_PK不爲空的行,那麼WHERE子句更合適。 – Skrol29 2011-04-06 11:53:10

+0

與出使用子句TOP(SELECT COUNT(iJobID_PK)FROM dbo.tbUS_Jobs),我不能使用視圖中的順序。 – 2011-04-06 11:54:41

+0

@ Skrol29 TOP(..)構造等於'SELECT TOP 100%'並指示SQL Server遵循'ORDER BY'。沒有TOP會忽略訂單。 – 2011-04-06 11:55:25

回答

4

第一個查詢只針對返回的行調用dbo.ufn_RecruiterCompanyName(),它對存儲的值進行過濾。對於第二個查詢,SQL Server需要爲所有行調用ufn。根據功能的不同,這可能會導致延遲。

入住這在查詢分析器,並儘量避免第二查詢^^

考慮看看自定義功能,我建議重寫該視圖使用連接表後。在這些函數中進行查找時,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 
+0

+1 - 我認爲函數調用是問題。 – JNK 2011-04-06 11:53:10

+0

是的你是對的。 dbo.ufn_RecruiterCompanyName()花費很多時間。 – 2011-04-06 12:19:53

+0

@Arindam - 你能發佈那個函數的代碼嗎?或者,是否可以在使用'INNER JOIN'或其他過濾器運行函數之前預先過濾結果? – JNK 2011-04-06 12:22:48

1

的問題是你的嵌套函數調用。

您在WHERE條款中調用ufn_RecruiterCompanyName,儘管是間接的。

這意思是,你的WHERE條款是非Sargable,並且必須運行功能每一行

該函數也調用ufn_GetParentRecruiterID。既然這是在第一個函數中的WHERE子句中,並且也是非Sargable,那麼您基本上在您的表中每行執行兩次表掃描。

將函數調用替換爲JOIN,您將看到性能的巨大提升。

+0

是的,這是主要問題。我正在嘗試通過加入。非常感謝。 – 2011-04-06 12:59:47