I have 3 tables that I need to join, these join together fine using indexes. However, we are transitioning over from using one legacy field as the identifier to another one in another table.
LEGACYID is that legacy field, while NEWID is the new field. Both fields are varchars.
Both fields are indexed exclusively with a btree index, both tables are MyISAM.
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
JOIN TBLQ Q ON Q.SHPID = S.SHPID
WHERE C.LEGACYID = '692041'
OR Q.NEWID = '692041'
This query takes 5.147 seconds, that’s 5 seconds longer than I expect.
When doing an EXPLAIN EXTENDED query the index type for NEWID is ALL i.e. full table scan , possible keys are (primary,NEWID) and key(null). If I remove the LEGACYID from the Or statement, explain says key (NEWID) will now be used. If I remove NEWID from the OR statement changes occur as following:
- the type of the table joins for (S,C) change from type ref to eq_ref
- key_len changes from 4 to 5 (on both)
- extra changes from empty to “Using where” .
With either one of the statements removed from the the OR statement the query runs at expected speeds.
Table Q has 183k records; C:115k; S:169k.
One last point. if I move the query placement:
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
LEFT JOIN TBLQ Q ON Q.SHPID = S.SHPID
AND Q.NEWID = '692041'
WHERE C.LEGACYID = '692041'
Although its not the same query, for the way the data works, it will provide the results I need, and the speed is down to under a .1 of a second again.
I did want to clarify that I don’t really need a query that works solution. Thanks to Ponies below that already has provided one. What I need to know is if anyone else has run into this problem and can explain why this is happening and what I can do for this simple or statement to use both indexes.
If you know there won’t be duplicates, change
UNIONtoUNION ALL(UNION ALLis faster because it doesn’t remove duplicates). Otherwise, use:ORs are notoriously bad performers, because it splinters the execution path. TheUNIONalleviates that splintering, and the combines the two results sets. That said,INis preferable toORs because though being logically the same, the execution ofINis generally more optimized.UNIONisn’t always the answerInvestigate many options, comparing the
EXPLAIN PLANoutput before determining a solution. I’ve come across a couple recently that perform better using a cursor than a single query using esoteric functionality.Also, make sure foreign key columns (what you’re using in the
ONclause when JOINing) are indexed. MySQL has started (v5.5+?) to automatically do this when a foreign key constraint is made, but that’s only for InnoDB tables.