その理由は、またはの使用にあります 場所の条件 条項。
説明のために、今回はid = 5
のみを使用してクエリを再実行してみてください 条件を設定し、(EXPLAIN出力)を取得します:
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| 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 |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
また、今回はparent_id = @last_id OR parent_id = 5
のみを使用します 条件を設定し、取得します:
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| 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は、同じクエリで複数のインデックスを処理するのはあまり得意ではありません。 AND条件を使用すると状況が少し良くなります。 index_merge> indexunionよりも最適化 最適化。
バージョンが進むにつれて状況は改善していますが、バージョン5.5
でクエリをテストしました 、これは現在の最新の製品版であり、結果は説明どおりです。
これが難しい理由を説明するために、次のことを考慮してください。2つの異なるインデックスが、クエリの2つの異なる条件に応答します。 id = 5
に答えます 、もう1つはparent_id = @last_id OR parent_id = 5
(ところで、またはに問題はありません 後者の内部では、両方の用語が同じインデックス内から処理されるためです。
両方に答えることができる単一のインデックスはないため、FORCE INDEX
命令は無視されます。 FORCE INDEX
を参照してください MySQLはを使用する必要があると言います テーブルスキャンのインデックス。これは、テーブルスキャンで複数のインデックスを使用する必要があることを意味するものではありません。
したがって、MySQLはここのドキュメントのルールに従います。しかし、なぜこれがそれほど複雑なのですか?両方のインデックスを使用して回答するには、MySQLは両方から結果を収集する必要があるため、2番目のインデックスを管理する間、一時的なバッファに一方を保存します。次に、そのバッファーを調べて、同一の行をフィルターで除外する必要があります(一部の行がすべての条件に適合する可能性があります)。次に、そのバッファをスキャンして結果を返します。
しかし、待ってください。そのバッファ自体はインデックス付けされていません。重複のフィルタリングは明らかな作業ではありません。そのため、MySQLは元のテーブルで作業してそこでスキャンを実行し、その混乱をすべて回避することを好みます。
もちろん、これは解決可能です。 Oracleのエンジニアはまだこれを改善する可能性があります(最近、クエリ実行計画の改善に懸命に取り組んでいます)が、これがTODOタスクにあるのか、それとも優先度が高いのかはわかりません。