@parameter IS NULL 可以減慢查詢的執行速度嗎?
選項1:
CREATE PROCEDURE [dbo].[GetStudents] @MinimumAge int = NULL AS select * from Students s where @MinimumAge is null or s.Age >= @MinimumAge
選項 2:
CREATE PROCEDURE [dbo].[GetStudents] @MinimumAge int = NULL AS IF @MinimumAge IS NULL BEGIN select * from Students s END ELSE BEGIN select * from Students s where s.Age >= @MinimumAge END
選項 1 會比選項 2 慢,因為它有額外的
WHERE
子句嗎?或者 SQL Server 會處理這個問題嗎?我認為選項 1 很好,因為我不必複製程式碼,除非它更慢。原始程序有很多行程式碼。所以我不想只為一個條件複製所有程式碼,除非它是唯一的好選擇。
列上有索引
age
,它不允許空值。問題是,實際 SP 有很多行程式碼 - 所以我不想複製所有程式碼只是為了添加一個 where 條件,除非它是唯一的好選擇。
你也可以試試:
WHERE Age >= COALESCE(@MnimumAge, 0)
假設 0 不是有效的
Age
. 否則,您可以使用 -1 而不是 0 作為預設值。這將允許在鍵上的索引上進行查找
Age
。另一個主要選項是添加
OPTION (RECOMPILE)
到語句中:CREATE PROCEDURE [dbo].[GetStudents] @MinimumAge int = NULL AS BEGIN SELECT S.* FROM dbo.Students AS S WHERE @MinimumAge IS NULL OR S.Age >= @MinimumAge OPTION (RECOMPILE); END;
@MinimumAge
當語句(不是整個過程)被重新編譯時,這會在每次呼叫上增加一點成本,但它允許參數嵌入優化,因此您將獲得針對每次執行的特定值的最佳執行計劃。有關詳細資訊,請參閱Paul White 的參數嗅探、嵌入和RECOMPILE
選項。您可能還想閱讀Aaron Bertrand的 #BackToBasics : An Updated “Kitchen Sink” Example並查看相關的 Q & A SQL Server–If 儲存過程和計劃記憶體中的邏輯
根據我的經驗,最好的解決方案是第三種解決方案,它遵循“一個程序完成一項任務”的規則。您的程序目前服務於 2 個任務 - 返回所有員工,並根據年齡返回一個子集。兩種不同的事情,在一個程序中,是未來悲傷的根源。可能不像你給出的簡化語句,但很可能是更複雜的程式碼。
這是我的做法:
CREATE PROCEDURE [dbo].[GetAllStudents] AS BEGIN SELECT * FROM Students; END; GO CREATE PROCEDURE [dbo].[GetOldStudentsByAge] @MinimumAge INT AS BEGIN SELECT * FROM Students AS a WHERE s.Age >= @MinimumAge; END; GO CREATE PROCEDURE [dbo].[GetStudents] @MinimumAge INT = NULL AS BEGIN IF @MinimumAge IS NULL EXECUTE dbo.[GetAllStudents]; ELSE EXECUTE dbo.[GetOldStudentsByAge] @MinimumAge; END;
現在,每個過程都有一個目的,使用一個沒有應用程序邏輯的簡單語句,它更清晰,更容易閱讀和維護恕我直言,並且由於後續執行使用不同的邏輯,您將不會遇到參數/記憶體問題,如每個子程序只有一個好的計劃。如果 @MinimumAge 值差異顯著以至於需要不同的計劃,您仍然可能遇到參數問題。這也可以解決,但這是一個單獨的問題。