I’m writing a general search Stored Procedure to search in a table based on many filters which user can select in the UI (using MS-SQL 2008).
Here is ther simplified version:
CREATE PROCEDURE SearchAll
@FirstName NVARCHAR(MAX) = NULL,
@LastName NVARCHAR(MAX) = NULL,
@Age INT = NULL
AS
SELECT *
FROM persons
WHERE
(@FirstName IS NULL OR FirstName = @firstname)
AND (@LastName IS NULL OR LastName = @LastName)
AND (@Age IS NULL OR Age = @Age)
It seems that if I pass NULL to @Age there’ll be no performance cost. But, when I’m testing with huge amount of data, I have a great perfomance lost!
Here is the queries which are the same logicaly but VERY different practically:
DECLARE @FirstName NVARCHAR(MAX) = NULL
DECLARE @Age INT = 23
------------First slow------------
SELECT *
FROM persons
WHERE
(@FirstName IS NULL OR FirstName = @firstname)
AND (@Age IS NULL OR Age = @Age)
------------Very fast------------
SELECT *
FROM persons
WHERE
Age = @Age
Did is miss a point?
I know that SQL engine finds the best match for indexes, and … (before running the query),but it’s obvious that: @FirstName IS NULL and there’s no need to analyse anything.
I’ve also tested ISNULL function in the query (the same result).
Queries that contain this construct of
@variable is null or @variable = columnare a performance disaster. This is because SQL plans are created so they work for any value of the variable. For a lengthy discussion of the topic, the problems and possible solutions see Dynamic Search Conditions in T-SQL