In MYSQL, some code from a WordPress plugin that I don’t want to change too much is running the following query:
SELECT * WHERE cond1 AND (field1 = val1 OR field2 = val2)
However, it runs very slowly despite that there are indexes on val1 and val2. (the slow query log confirms that it scans all rows.) Can I hint MYSQL that it should always expand the formula to the following equivalent but faster form?
SELECT * WHERE cond1 AND (field1 = val1)
UNION
SELECT * WHERE cond1 AND (field2 = val2)
This would reduce the number of rows scanned dramatically, so it would yield vastly superior performance. I also wonder the same about
SELECT * WHERE cond1 AND (field1 in (val1, val2))
Thanks!
Edit: some info about the table and the query explanation are here at http://pastebin.com/Qd1ZaVKD but it seems inconsistent. If I run the query from myphpadmin sometimes a slow query log entry is generated and sometimes not, even if it continues to be generated when other users are causing such a row.
It first depends on
cond1, and then on the cardinality offield1andfield2under that condition:If
cond1involves direct comparisons of columns with constant values (i.e. an index can help to resolve it), then a composite index withfield1and/orfield2may help (see below).If
cond1involves manipulations on columns—e.g. applying a function or other operations, such asmy_int + 5 = 3orDATE(my_timestamp) > NOW()—then an index cannot help; however, note that both of those examples can be rewritten to be index-friendly:my_int = 3 - 5, which is obviously equivalent tomy_int = -2; andmy_timestamp >= CURDATE() + INTERVAL 1 DAY.It’s only ever worth creating indexes that have relatively high cardinality (i.e. can quickly distinguish between many records), otherwise using it will be little better than a full table scan whilst slowing down table write operations and consuming additional storage and memory space. Consider not only the cardinality of
cond1,field1andfield2, but also that ofcond1together with each of the fields.Assuming that they all have high cardinality, your best bet would be to achieve an
index_merge(union access) with two composite indexes on each of(cond1, field1)and(cond1, field2).