4
EXPLAIN SELECT
*
FROM
content_link link
STRAIGHT_JOIN
content
ON
link.content_id = content.id
WHERE
link.content_id = 1
LIMIT 10;

+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+
| id | select_type | table   | type  | possible_keys | key        | key_len | ref   | rows | Extra |
+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+
|  1 | SIMPLE      | link    | ref   | content_id    | content_id | 4       | const |    1 |       |
|  1 | SIMPLE      | content | const | PRIMARY       | PRIMARY    | 4       | const |    1 |       |
+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+

ただし、WHEREを削除すると、クエリはキーの使用を停止します(明示的に強制した場合でも)

EXPLAIN SELECT
*
FROM
content_link link FORCE KEY (content_id)
STRAIGHT_JOIN
content
ON
link.content_id = content.id
LIMIT 10;

+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+
| id | select_type | table   | type   | possible_keys | key     | key_len | ref                    | rows    | Extra       |
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+
|  1 | SIMPLE      | link    | index  | content_id    | PRIMARY | 7       | NULL                   | 4555299 | Using index |
|  1 | SIMPLE      | content | eq_ref | PRIMARY       | PRIMARY | 4       | ft_dir.link.content_id |       1 |             |
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+

これに対する回避策はありますか?

2番目の例でテーブル全体を選択していることに気付きましたが、なぜmysqlは、とにかく私のFORCEを無視し、キーを使用しないと突然決定するのですか?キーがないと、クエリは10分ほどかかります。

4

3 に答える 3

4

インデックスはテーブル内をすばやく検索するのに役立ちますが、テーブル全体を選択すると処理が遅くなります。したがって、MySQLはインデックスを無視するのが正しいです。

あなたの場合、インデックスにはMySQLには知られていない隠れた副作用があるかもしれません。たとえば、内部結合が数行だけ保持される場合、インデックスは処理を高速化します。しかし、MySQLは、明示的なヒントがなければそれを知ることができません。

例外があります。選択したすべての列がインデックス内にある場合でも、すべての行を選択するとインデックスは役立ちます。たとえば、LastNameにインデックスがある場合でも、次のクエリはインデックスの恩恵を受けます。

select LastName from orders

しかし、これはしません:

select * from Orders
于 2009-06-03T17:13:49.617 に答える
4

FORCEは少し誤称です。MySQLドキュメントの内容は次のとおりです(私の強調):

FORCE INDEXを使用することもできます。これは、USE INDEX(index_list)のように機能しますが、テーブルスキャンは非常にコストがかかると想定されています。つまり、テーブルスキャンは、指定されたインデックスの1つを使用してテーブル内の行を検索する方法がない場合にのみ使用されます。

実際には行を「検索」していない(すべてを選択している)ので、テーブルスキャンは常に最速になり、オプティマイザーは、何を言っているかにかかわらず、それを知るのに十分賢いです。

ETA:

主キーにORDERBYを一度追加してみてください。そうすれば、インデックスが使用されるに違いありません。

于 2009-06-03T17:21:08.470 に答える
0

あなたは価値観content_idを受け入れているようNULLです。

MySQLオプティマイザーは、クエリがインデックスを使用するだけですべての値を返すという保証はないと考えています(ただし、実際には、で列を使用するため、保証はありますJOIN

そのため、全表スキャンに戻ります。

条件を追加するNOT NULL

SELECT  *
FROM    content_link link FORCE KEY (content_id)
STRAIGHT_JOIN
        content
ON      content.id = link.content_id
WHERE   link.content_id IS NOT NULL
LIMIT 10;

NOT NULLまたは、列を次のようにマークします。

ALTER TABLE content_link MODIFY content_id NOT NULL

アップデート:

これは、のバグ45314で確認されていMySQLます。

于 2009-06-03T17:31:42.527 に答える