MySQL + Drupal: индекс игнорируется в INNER JOIN - PullRequest
0 голосов
/ 19 мая 2009

Наше окружение: Drupal + MySQL

Изучение журнала запросов показывает, что следующий запрос, исходящий из функции node_load ядра Drupal, занимает значительное время.

EXPLAIN в запросе node_load показывает, что индекс не используется в таблице USER.

mysql> explain SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, 
    n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, 
    r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data 
FROM xyz_node n 
INNER JOIN xyz_users u ON n.uid = u.uid 
INNER JOIN xyz_node_revisions r ON r.vid = n.vid;

+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref          | rows | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+
|  1 | SIMPLE      | u     | ALL    | PRIMARY       | NULL    | NULL    | NULL         |  181 |             | 
|  1 | SIMPLE      | n     | ref    | vid,uid       | uid     | 4       | xyz.u.uid |    9 | Using where | 
|  1 | SIMPLE      | r     | eq_ref | PRIMARY       | PRIMARY | 4       | xyz.n.vid |    1 |             | 
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+

Есть идеи, что может происходить, и как я могу заставить MYSQL использовать Index для этого запроса?

Ответы [ 3 ]

3 голосов
/ 19 мая 2009

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

Первым делом я бы запустил ANALYZE TABLE для всех трех таблиц, задействованных в запросе. Это обновляет статистику таблиц и распределение хранимых ключей и позволяет оптимизатору соединений принимать более правильные решения. Затем запустите оператор EXPLAIN и посмотрите, изменился ли он.

Если оно не изменилось, возможно, вам придется прибегнуть к использованию ключевого слова STRAIGHT_JOIN. Это заставляет оптимизатор объединения объединять таблицы в точном порядке, указанном в запросе. Чтобы определить, следует ли вам это делать, вы должны взять произведение всех значений rows из результата EXPLAIN и сравнить его с фактическим количеством строк, возвращаемых запросом. Поэтому в этом случае сравните 1629 (181x9x1) с фактическим количеством строк. Если они существенно различаются, может потребоваться STRAIGHT_JOIN (используется как ключевое слово для SELECT, т. Е. SELECT STRAIGHT_JOIN n.nid ... и т. Д.).

Кроме того, есть способ указать MySQL использовать определенный индекс , но я не думаю, что он будет работать для вашей пользовательской таблицы в этом запросе, как сейчас, так как не является WHERE пунктом. Если вы в конечном итоге используете STRAIGHT_JOIN, возможно, вам это понадобится, но в этом случае MySQL, вероятно, получит первичный ключ, если пользовательская таблица не была первой таблицей в объединении.

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

Этот запрос не выглядит как , который медленный для того, что он есть. Без предложения where можно ожидать где-нибудь полное сканирование таблицы, и MySQL сократил его до 1700 проверенных строк. Кажется, что это было бы проблемой только в том случае, если это был запрос с высокой интенсивностью использования, и в этом случае вы можете изучить базовую архитектуру, которая (без предложения WHERE) предполагает выполнение запроса, который затронет каждого пользователя в системе. , и будет становиться все тяжелее по мере добавления новых пользователей.

1 голос
/ 19 мая 2009

Поскольку MySQL может использовать только один индекс на таблицу для запроса, иногда вы можете получить "сканирование" индекса свободного диапазона, просто добавив это, казалось бы, бесполезное условие.

WHERE u.uid > 0

Попробуйте добавить это предложение, скорее всего, сканирование таблицы ALL изменится на «диапазон», что лучше, чем сканирование всей таблицы.

0 голосов
/ 04 октября 2009

Может ли это помочь?

В узле таблицы создайте индекс для (uid, vid) ALTER TABLE 'xyz_node' ADD INDEX user_ver ('uid,' vid ') (Обратите внимание на 2-ю строку в выводе объяснения .. под заголовком возможные ключи .. вы видите vid, uid)

...