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 index efficient.
SQL Server
will just optimize out one of the queries, depending on the value of @bar
, and will use the index on foo
to execute the remaining query.
Update:
Table master
has 20,000,000
records with 2,000,000
records having name = 't'
.
This query:
DECLARE @s INT
SET @s = 2
SELECT *
FROM master
WHERE (@s = 1 AND name IN ('t')) OR
(@s = 2 AND name IN ('zz'))
uses an 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 query:
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
of two separate queries (one of them being optimized out), 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)