The reason is because the OR clause is used in the WHERE clause .
To illustrate this, try executing the request again, this time only with the condition id = 5
and get (EXPLAIN output):
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | | | 1 | PRIMARY | tree | const | PRIMARY,index_both | PRIMARY | 4 | const | 1 | | | 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
And again, this time only with the condition parent_id = @last_id OR parent_id = 5
and we get:
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | | | 1 | PRIMARY | tree | ALL | index_parent_id | NULL | NULL | NULL | 10 | Using where | | 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
MySQL is not very good at handling multiple indexes in a single query. Things are a little better with the terms AND; it is more likely that index_merge optimizations than index union .
Things improve as versions progress, but I tested your request on version 5.5
, which is on the current latest production version, and the results, as you described.
To explain why this is difficult, consider: two different indexes will respond to two different query conditions. One answer will be responsible for id = 5
, and the other for parent_id = @last_id OR parent_id = 5
(BTW without problems with OR inside the latter, since both terms are processed from the same index).
There is no single index that can answer for both, and therefore the FORCE INDEX
command is ignored. See, FORCE INDEX
says that MySQL should use an index to scan a table. This does not mean that more than one index must be used to scan a table.
So, MySQL follows the documentation rules here. But why is it so complicated? Since MySQL must collect results from both for a response using both indexes, store them in a temporary buffer, controlling the second. Then you need to go through this buffer to filter out identical lines (it is possible that some line meets all conditions). And then scan this buffer to return the results.
But wait, this buffer is not indexed by itself. Filtering duplicates is not an obvious task. Therefore, MySQL prefers to work with the source table and scan there, and avoid all this mess.
Of course, this is solvable. Oracle engineers can still improve this (they have been working hard lately to improve the query of execution plans), but I donβt know if it is on the TODO task, or if it has high priority.