Sql-Server

@parameter IS NULL 可以減慢查詢的執行速度嗎?

  • June 5, 2020

選項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 值差異顯著以至於需要不同的計劃,您仍然可能遇到參數問題。這也可以解決,但這是一個單獨的問題。

引用自:https://dba.stackexchange.com/questions/208824