Reputation: 33
Running the following a query of the following form takes over 60 seconds to process.
SELECT *
FROM View_A
WHERE ( Column_1 IN (SELECT Column_1 FROM View_B WHERE Column_2 = 'my_test_value' OR Column_3 = 'my_test_value'))
Using a Temp Table the batch returns the same result in less than 1 second.
SELECT Column_1
INTO #temp1
FROM View_B
WHERE Column_2 = 'my_test_value' OR Column_3 = 'my_test_value'
SELECT *
FROM View_A
WHERE Column_1 IN (SELECT * FROM #temp1)
Running the original query with either of the tests removed (no OR) results in a sub-second result. Also running the sub-query (SELECT Column_1 FROM View_B WHERE Column_2 = 'my_test_value' OR Column_3 = 'my_test_value')
without the surrounding query is also sub-second in response.
I tried using UNION ALL
but in some cases both column 2 and column 3 have the same value due to the architecture of the legacy application. As a result union all
gives me duplicate rows. And some of the columns in view A are text
so a straight union
complains that it can not compare the column values.
Columns 1,2 & 3 are all indexed and the relationships between tables referenced in Views A & B are based on foreign key constraints.
Any insight on where to look next would be greatly appreciated. I need to get a concise SQL Query that performs like the temp table solution.
Upvotes: 0
Views: 65
Reputation: 27202
Try using a UNION
- OR
is notorious for performing badly in certain queries.
As you have indicated that a text
column is preventing the union
from working, instead of using *
(which is never best practice anyway), list your columns and convert any text
columns to varchar(max)
.
SELECT Col1, Col2, convert(varchar(max),TextCol1) -- And so on
FROM View_A
WHERE (Column_1 IN (SELECT Column_1 FROM View_B WHERE Column_2 = 'my_test_value'))
union
SELECT Col1, Col2, convert(varchar(max),TextCol1) -- And so on
FROM View_A
WHERE (Column_1 IN (SELECT Column_1 FROM View_B WHERE Column_3 = 'my_test_value'));
As you have indicated that a union
does improve the performance (to 9s), but that its still not fast enough, try a window function i.e. where you assign each row a row number based on whether it is unique or not (as I don't know your schema I don't know what that is, so you need to replace the ColUnique
with the actual unique condition.
So the steps are:
UNION ALL
select ColUnique, Col1, Col2, Col3
from (
select ColUnique, Col1, Col2, Col3
, row_number() over (partition by ColUnique order by ColUnique) row#
from (
SELECT ColUnique, Col1, Col2, Col3 -- and so on
FROM View_A
WHERE (Column_1 IN (SELECT Column_1 FROM View_B WHERE Column_2 = 'my_test_value'))
union all
SELECT ColUnique, Col1, Col2, Col3
FROM View_A
WHERE (Column_1 IN (SELECT Column_1 FROM View_B WHERE Column_3 = 'my_test_value'))
) X
) Y
where Y.row# = 1;
Upvotes: 1