I would re-write the query to combine two separate sets, avoiding the OR
in the WHERE
clause.
Something like this:
( SELECT a1.field1
, b1.field2
FROM tableA a1
JOIN tableB b1
ON b1.somefield = a1.somefield
WHERE a1.field1 = 'value1'
)
UNION ALL
( SELECT a2.field1
, b2.field2
FROM tableA a2
JOIN tableB b2
ON b2.somefield = a2.somefield
WHERE b2.field2 = 'value2'
HAVING NOT (a2.field1 <=> 'value1')
)
That query should be able to make effective use of these indexes, for the SELECT
... ON tableA (field1,somefield,...)
... ON tableB (somefield,field2,...)
and for the second SELECT
... ON tableA (somefield,field1,...)
... ON tableB (field2,somefield,...)
Use EXPLAIN to see the execution plan
Another way to look at the set being returned is as the combination of three sets...
- rows that match on both a.field1 and b.field2
- rows that match on a.field1 but not on b.field2
- rows that match on b.field2 but not on a.field1
The first subset would the original query, replacing OR
with AND
.
Each of the last two subsets could be returned
SELECT ...
FROM a
JOIN b
ON ...
WHERE a.field1 = 'value1'
AND NOT ( b.field2 <=> 'value2' )
and
SELECT ...
FROM a
JOIN b
ON ...
WHERE b.field2 = 'value2'
AND NOT ( a.field1 <=> 'value1' )
Provide suitable indexes for each SELECT, and combine the sets with UNION ALL
set operator.