Reputation: 1340
While adding OR operator in WHERE Clause it takes more time for execution to complete.
I am using two tables in my Stored Procedure.
I need to check two conditions in my query and which is also very simple.
But unfortunately we are unable to create Index for these table columns.
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID=TBL2.ID
WHERE (@Code = TBL1.Code OR @Code IS NULL)
AND (@Port = TBL1.POL OR @Port = TBL1.POD OR @Port IS NULL)
Even though, I checked twice without these conditions it takes 0.35 sec with 9k rows
But when it add these conditions in where
clause it takes more than 2 min.
Note: Sorry I'm unable to provide sample data for this issue.
Upvotes: 0
Views: 1029
Reputation: 1270391
I would suggest that you use dynamic SQL:
declare @sql nvarchar(max);
set @sql = N'
SELECT *
FROM TBL1 INNER JOIN
TBL2
ON TBL1.ID = TBL2.ID
WHERE [where]
;
declare @where nvarchar(max)';
set @where = @where + (case when @code is not null then N'tbl1.code = @code and' else '' end);
set @where = @where + (case when @port is not null then N'@port in (tbl1.pol, tbl1.pod) and'
set @sql = @sql + @where + N' 1=1';
exec sp_executesql @sql,
N'@code <type here>; @port <type here>',
@code=@code, @port=@port;
This generates only the code that is needed, so it will be optimized correctly.
The overhead of recompiling the query should be minimal compared to the time used for running the query (unless the two tables are trivially small).
Upvotes: 1
Reputation: 12041
You could try something like this, using CASE:
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID=TBL2.ID
WHERE 1 = (CASE WHEN @Code IS NULL THEN 1
WHEN @Code = TBL1.Code THEN 1 END)
AND 1 = (CASE WHEN @Port IS NULL THEN 1
WHEN @Port = TBL1.POL THEN 1
WHEN @Port = TBL1.POD THEN 1 END)
I've sometimes experienced using "OR" to be the slowest alternative. YMMV. You could also try query hints.
Upvotes: 2
Reputation: 27289
If you absolutely have no option to add indexes you can sometimes improve OR
performance by converting your query to use UNION ALL
- which if I have got it right gives the following 6 components to cover all permutations.
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code = TBL1.Code AND @Port = TBL1.POL
UNION ALL
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code = TBL1.Code AND @Port = TBL1.POD
UNION ALL
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code = TBL1.Code AND @Port IS NULL
UNION ALL
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code IS NULL AND @Port = TBL1.POL
UNION ALL
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code IS NULL AND @Port = TBL1.POD
UNION ALL
SELECT *
FROM TBL1
INNER JOIN TBL2 ON TBL1.ID = TBL2.ID
WHERE @Code IS NULL AND @Port IS NULL;
Upvotes: 1
Reputation: 521979
You may try adding the following index to the first table:
CREATE INDEX idx1 ON TBL1 (Code, POL, POD, ID);
Assuming SQL Server would use the above index, it would execute the query by scanning TBL2
but using the index for the join and where restrictions. You may also try this version of the index:
CREATE INDEX idx1 ON TBL1 (ID, Code, POL, POD);
Upvotes: 1