2011-09-21 126 views
1

在存儲過程的where子句中使用函數調用會降低sql server 2005中的性能?在存儲過程sql server 2005中使用函數調用?

SELECT * FROM Member M 
WHERE LOWER(dbo.GetLookupDetailTitle(M.RoleId,'MemberRole')) != 'administrator' 
AND LOWER(dbo.GetLookupDetailTitle(M.RoleId,'MemberRole')) != 'moderator' 

在此查詢GetLookupDetailTitle是用戶定義的函數和LOWER()是內置的功能我問大約兩個。

+0

絕對沒有足夠的信息!什麼函數調用?我們可以看到SQL嗎? –

+4

將函數應用於where子句中的列會否定使用該列上的任何索引的能力。這通常被稱爲不可查詢的查詢。 –

回答

1

是的。

這些都是儘可能避免的做法。

almost any函數應用於列使得表達式不可用,這意味着無法使用索引,即使未對列索引,也會使基數估計對於計劃的其餘部分不正確。

此外,您的dbo.GetLookupDetailTitle標量函數看起來好像數據訪問,它應該內聯到查詢中。

查詢優化程序不會從標量UDF內聯邏輯,並且您的查詢將針對源數據中的每一行執行此查找,這將有效地實施嵌套循環連接,而不管其是否適合。

此外,由於2個函數的調用,每行實際上會發生兩次。你或許應該改寫爲類似

SELECT M.* /*But don't use * either, list columns explicitly... */ 
FROM Member M 
WHERE NOT EXISTS(SELECT * 
       FROM MemberRoles R 
       WHERE R.MemberId = M.MemberId 
       AND R.RoleId IN (1,2) 
       ) 

不要試圖更換文字值1,2與更具描述性的名稱變量,這也可以搞砸基數估計。

+0

請參閱[本文](http://stackoverflow.com/questions/799584/what-makes-a-sql-statement-sargable)以獲取有關非可疑查詢的更多信息以及避免它們的一些策略。 – Maciej

+0

確定將內置函數,如LOWER,UPPER,LTRIM命中性能,如果我在where子句中使用它? –

+0

@ user441052 - 是的,他們將阻止使用索引來查找與謂詞匹配的行。如果您希望區分大小寫比較,請確保您將數據存儲在不區分大小寫的排序規則的列中。如果你通常留下尾隨的空間來彌補你的比較,那麼做一次性整理並修復你的查詢,以便在'insert' /'update'時間被刪除。 –

0

使用WHERE子句中的函數強制執行表掃描。

沒有辦法使用索引,因爲引擎無法知道結果會是什麼,直到它在表中的每一行上運行該函數。

+0

'LEFT'不是可靠的AFAIK。 [它包含在這個連接項中,可能是但不是。](http://connect.microsoft.com/SQLServer/feedback/details/526431/make-more-functions-sargable) –

+0

@MartinSmith - 原以爲是,但事實並非如此。更正了帖子。 – JNK

0

你可以同時避免用戶自定義功能和內置的

  • 定義管理員和版主角色「神奇」的價值觀和比較Member.RoleId針對這些標量

  • 定義IsAdministrator和IsModerator在MemberRole表上標誌並加入成員以過濾這些標誌

相關問題