Индекс Mysql игнорируется - PullRequest
4 голосов
/ 03 июня 2009
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 |             |
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+

Есть ли обходные пути?

Я понимаю, что выбираю всю таблицу во втором примере, но почему mysql вдруг решает, что она все равно проигнорирует мою СИЛУ и не использует ключ? Без ключа запрос занимает минут 10 .. тьфу.

Ответы [ 3 ]

4 голосов
/ 03 июня 2009

FORCE - немного неправильное название. Вот что говорят документы MySQL (выделено мое):

Вы также можете использовать FORCE INDEX, который действует как USE INDEX (index_list), но с добавлением, что сканирование таблицы предполагается очень дорогим. Другими словами, сканирование таблицы используется, только если нет способа использовать один из заданных индексов для поиска строк в таблице.

Поскольку на самом деле вы не «находите» какие-либо строки (вы выбираете их все), сканирование таблицы будет всегда быстрым, а оптимизатор достаточно умен, чтобы знать, что, несмотря на что вы им говорите.

ETA:

Попробуйте добавить ORDER BY на первичный ключ один раз, и я уверен, что он будет использовать индекс.

4 голосов
/ 03 июня 2009

Индекс помогает быстро искать внутри таблицы, но он просто замедляет работу, если вы выбираете всю таблицу. Так что MySQL правильно игнорирует индекс.

В вашем случае, возможно, индекс имеет скрытый побочный эффект, который не известен MySQL. Например, если внутреннее соединение выполняется только для нескольких строк, индекс ускорит процесс. Но MySQL не может знать это без явного намека.

Существует исключение: когда каждый выбранный вами столбец находится внутри индекса, индекс по-прежнему полезен, если вы выбираете каждую строку. Например, если у вас есть индекс LastName, следующий запрос по-прежнему будет использовать индекс:

select LastName from orders

Но этот не будет:

select * from Orders
0 голосов
/ 03 июня 2009

Ваш 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.

...