Есть ли способ заставить порядок выполнения MySQL? - PullRequest
23 голосов
/ 11 августа 2010

Я знаю, что могу изменить способ выполнения запроса MySQL с помощью ключевого слова FORCE INDEX (abc).Но есть ли способ изменить порядок выполнения?

Мой запрос выглядит так:

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
  AND c.itemid = 123456

У меня есть ключ для каждого отношения / ограничения, которое я использую.Если я запускаю объяснение этого утверждения, я вижу, что mysql начинает запрашивать c первым.

id    select_type    table    type
1     SIMPLE         c        ref
2     SIMPLE         b        ref
3     SIMPLE         a        eq_ref

Однако я знаю, что запросы в порядке a -> b -> c будут быстрее (я это доказал). Есть ли способсказать mysql использовать определенный порядок?

Обновление: так я знаю, что a -> b -> c быстрее.

Вышеупомянутый запрос занимает 1,9 секунды и возвращает 7 строк.Если я изменю запрос на

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
HAVING c.itemid = 123456

, запрос будет завершен за 0,01 секунды (без необходимости получать 10000 строк).Однако это не элегантное решение, потому что этот запрос является упрощенным примером.В реальном мире у меня есть объединения из c в другие таблицы.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * [10] * * * * * * * * * * [10] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *.1024 * Переменная часть в этом запросе - c.itemid.Все остальное - фиксированные значения, которые не меняются.

Индексы настроены нормально, и mysql выбирает для меня правильные
  • между a и b, существует отношение 1: n (индекс PRIMARY равениспользуется)
  • между b и c существует отношение многие ко многим (используется индекс IDX_ITEMID)

дело в том, что mysql должен начать запрашивать таблицу aи работать это вниз до с, а не наоборот.Любые изменения, чтобы добиться этого.

Решение: Не совсем то, что я хотел, но, похоже, это работает:

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
  AND c.itemid = 123456
  AND f.id IN (
         SELECT DISTINCT table2.id FROM table1
         INNER JOIN table2 ON table1.id = table2.table1_id
         WHERE table1.itemtype = 1 AND table1.busy = 1)

Ответы [ 3 ]

35 голосов
/ 11 августа 2010

Возможно, вам нужно использовать STRAIGHT_JOIN.

http://dev.mysql.com/doc/refman/5.0/en/join.html

STRAIGHT_JOIN аналогично JOIN, за исключением того, что левая таблица всегда читается передправильный стол.Это может быть использовано в тех (немногих) случаях, когда оптимизатор соединений размещает таблицы в неправильном порядке.

3 голосов
/ 11 августа 2010

Вы можете использовать FORCE INDEX для принудительного выполнения порядка выполнения, и я уже делал это раньше.

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

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

3 голосов
/ 11 августа 2010

Вы можете попробовать переписать двумя способами

  • перенести некоторые условия WHERE в JOIN
  • ввести подзапросы, даже если они не нужны

Обе эти вещи могут повлиять на планировщика.

Однако первое, что нужно проверить, будет, если ваши характеристики обновлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...