Reputation: 2628
I'm developing a lot of stored procedures, and a great deal of them have a where clause similiar to the below.
WHERE
(CE.EnquiryDate >= @StartDate or @StartDate is null) and
(CE.EnquiryDate <= @EndDate or @EndDate is null) and
(CE.ClientID = @ClientID or @ClientID is null)
What concerns me is performance and the execution plans that are generated potentially causing issues down the track, i.e. if a plan is cached on first execution of the sp when only a clientid is passed then it is obviously going to be different to when a ClientID is not passed and a StartDate and EndDate are.
Am I going to be better off here splitting these off into multiple stored procedures or using OPTION (RECOMPILE)
to get a new plan on each run? Just wondering what the best approach is in the early stages of development.
Upvotes: 0
Views: 119
Reputation: 372
Try this :
WHERE
(CE.EnquiryDate >= ISNULL(@StartDate,CE.EnquiryDate)) and
(CE.EnquiryDate <= ISNULL(@EndDate,CE.EnquiryDate)) and
(CE.ClientID = ISNULL(@ClientID,CE.ClientID))
This can be used because of the "<=",">=" and "=" : not working with "<" or ">".
The goal is to avoir OR operator... Witch are so so slow. See execution plan.
See https://en.wikipedia.org/wiki/Boolean_algebra for further details about avoiding OR...
X OR Y = NOT (NOT X AND NOT Y)
Upvotes: 0
Reputation: 89256
The standard treatment of this question is Erland Sommarskog's Dynamic Search Conditions in T-SQL. Read that for a full discussion of the techniques and tradeoffs.
Since SQL 2008 SQL Server will optimize the query plan for this kind of query when using OPTION RECOMPILE. The predicates corresponding to null parameters will be removed from the query during compilation. So OPTION RECOMPILE is my default here, but if you have some search patterns you need to be super cheap, you may special-case them before a catch-all using OPTION RECOMPILE.
Something like:
IF (@StartDate is not null and @ClientId is not null)
BEGIN
SELECT *
FROM T
WHERE
(CE.EnquiryDate >= @StartDate) and
(CE.EnquiryDate <= @EndDate or @EndDate is null) and
(CE.ClientID = @ClientID )
RETURN
END
SELECT *
FROM T
WHERE
(CE.EnquiryDate >= @StartDate or @StartDate is null) and
(CE.EnquiryDate <= @EndDate or @EndDate is null) and
(CE.ClientID = @ClientID or @ClientID is null)
WITH (OPTION RECOMPILE)
Upvotes: 2