You see this kind of question all the time in newsgroups/forums, someone wants to return all the rows if nothing is passed in or just the rows that match the variable when something is passed in. Usually someone will reply with a suggestion to do something like this
WHERE (SomeColumn=@col OR @col IS NULL)
The problem with that approach is that it doesn't perform well, let's take a look, first create this table
- USE tempdb
- GO
- CREATE TABLE Test(SomeCol1 INT NOT NULL, Somecol2 INT NOT NULL)
- INSERT Test
- SELECT number,low FROM master..spt_values
- WHERE TYPE = 'p'
- CREATE INDEX ix_test ON Test(Somecol2)
- GO
Here is the query that uses the method described before, I am using AND 1=1 so that this query will match the one I will show later
- DECLARE @col INT
- SELECT @col = 1
- SELECT SomeCol2
- FROM Test
- WHERE 1 =1
- AND (SomeCol2=@col OR @col IS NULL)
Here is the query using dynamic SQL
- GO
- DECLARE @col INT
- SELECT @col = 1
- DECLARE @SQL NVARCHAR(4000)
- SET @SQL = 'SELECT SomeCol2
- FROM Test
- WHERE 1 =1'
- IF @col IS NOT NULL
- SET @SQL = @SQL + ' AND SomeCol2=@InnerParamcol '
- EXEC sp_executesql @SQL,N'@InnerParamcol INT',@col
Now let's run these queries and take a look at the reads
- SET STATISTICS IO ON
- GO
- DECLARE @col INT
- SELECT @col = 1
- SELECT SomeCol2
- FROM Test
- WHERE 1 =1
- AND (SomeCol2=@col OR @col IS NULL)
- GO
- DECLARE @col INT
- SELECT @col = 1
- DECLARE @SQL NVARCHAR(4000)
- SET @SQL = 'SELECT SomeCol2
- FROM Test
- WHERE 1 =1'
- IF @col IS NOT NULL
- SET @SQL = @SQL + ' AND SomeCol2=@InnerParamcol '
- EXEC sp_executesql @SQL,N'@InnerParamcol INT',@col
- SET STATISTICS IO OFF
- GO
(8 row(s) affected)
Table 'Test'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(8 row(s) affected)
Table 'Test'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
As you can see the dynamic SQL query only uses 2 reads where the other solution uses 6 reads.
Here is an image of the execution plan for both queries.
The execution plan show that the dynamic SQL is using a seek where the other query is using a scan
As you can see, there is a place for dynamic SQL and if you use it correctly you will also get plan reuse, take a look at the post Changing exec to sp_executesql doesn't provide any benefit if you are not using parameters correctly to find out how to use dynamic SQL correctly
[EDIT]
Someone on twitter suggested to try this query
- DECLARE @col INT
- SELECT @col = 1
- SELECT SomeCol2
- FROM Test
- WHERE 1 =1
- AND SomeCol2 = isnull(@col,SomeCol2)
That query also does an index scan.
Here is the execution plan in text for both of the queries that cause the scan
|--Index Scan(OBJECT:([tempdb].[dbo].[Test].[ix_test]),
WHERE:([tempdb].[dbo].[Test].[Somecol2]=isnull([@col],[tempdb].[dbo].[Test].[Somecol2])))
|--Index Scan(OBJECT:([tempdb].[dbo].[Test].[ix_test]),
WHERE:([tempdb].[dbo].[Test].[Somecol2]=[@col] OR [@col] IS NULL))
There was also a comment about recompiles, when you use sp_executesql you should not get recompiles when changing the value that you are passing in. I ran this query
- DECLARE @col INT
- SELECT @col = 1
- DECLARE @SQL NVARCHAR(4000)
- SET @SQL = 'SELECT SomeCol2
- FROM Test
- WHERE 1 =1'
- IF @col IS NOT NULL
- SET @SQL = @SQL + ' AND SomeCol2=@InnerParamcol '
- EXEC SP_EXECUTESQL @SQL,N'@InnerParamcol INT',@col
- Go
- DECLARE @col INT
- SELECT @col = 2
- DECLARE @SQL NVARCHAR(4000)
- SET @SQL = 'SELECT SomeCol2
- FROM Test
- WHERE 1 =1'
- IF @col IS NOT NULL
- SET @SQL = @SQL + ' AND SomeCol2=@InnerParamcol '
- EXEC SP_EXECUTESQL @SQL,N'@InnerParamcol INT',@col
- Go
- DECLARE @col INT
- SELECT @col = 3
- DECLARE @SQL NVARCHAR(4000)
- SET @SQL = 'SELECT SomeCol2
- FROM Test
- WHERE 1 =1'
- IF @col IS NOT NULL
- SET @SQL = @SQL + ' AND SomeCol2=@InnerParamcol '
- EXEC SP_EXECUTESQL @SQL,N'@InnerParamcol INT',@col
- Go
And then I ran a trace checking for SQL:StmtRecompile
Here is the output from that trace
[/EDIT]
*** Remember, if you have a SQL related question, try our Microsoft SQL Server Programming forum or our Microsoft SQL Server Admin forum






can you provide an example of the dynamic query if you have, lets say 6, parameters?
LTD Social Sitings
Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.