SELECT * FROM … WHERE @bar = 'BAR' AND foo IN ('FOO', 'BAR', 'BAZ') UNION ALL SELECT * FROM … WHERE @bar = 'BAZ' AND foo IN ('FOOBAR', 'FOOBAZ')
This will be most effective on the index.
SQL Server simply optimizes one of the queries depending on the @bar value and will use the index on foo to execute the remaining query.
Update:
The master table has 20,000,000 records with 2,000,000 records having name = 't' .
This request:
DECLARE @s INT SET @s = 2 SELECT * FROM master WHERE (@s = 1 AND name IN ('t')) OR (@s = 2 AND name IN ('zz'))
uses INDEX SCAN and returns nothing in 4 seconds:
|--Parallelism(Gather Streams) |--Index Scan(OBJECT:([test].[dbo].[master].[ix_name_desc]), WHERE:([@s]=(1) AND [test].[dbo].[master].[name]='t' OR [@s]=(2) AND [test].[dbo].[master].[name]='zz'))
This request:
DECLARE @s INT SET @s = 2 SELECT * FROM master WHERE @s = 1 AND name IN ('t') UNION ALL SELECT * FROM master WHERE @s = 2 AND name IN ('zz')
uses CONCATENATION two separate queries (one of which is optimized) and returns instantly:
|--Concatenation |--Parallelism(Gather Streams) | |--Filter(WHERE:(STARTUP EXPR([@s]=(1)))) | |--Index Seek(OBJECT:([test].[dbo].[master].[ix_name_desc]), SEEK:([test].[dbo].[master].[name]='t') ORDERED FORWARD) |--Filter(WHERE:(STARTUP EXPR([@s]=(2)))) |--Index Seek(OBJECT:([test].[dbo].[master].[ix_name_desc]), SEEK:([test].[dbo].[master].[name]='zz') ORDERED FORWARD)
source share