Подтвердить что ты не робот

Есть ли способ заставить порядок выполнения MySQL?

Я знаю, что могу изменить способ выполнения 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 секунды (без использования 10 000 строк). Однако это не изящное решение, потому что этот запрос является упрощенным примером. В реальном мире я присоединяюсь от c к другим таблицам. Поскольку HAVING - это фильтр, который выполняется по всему результату, это означало бы, что я вытащил бы некоторые магниты больше записей из db, чем nescessary.

Edit2: Только некоторая информация:

  • переменной в этом запросе является c.itemid. Все остальное - фиксированные значения, которые не изменяются.
  • Индексы настроены отлично, а mysql выбирает нужные для меня
    • между a и b существует отношение 1: n (используется индекс PRIMARY)
    • между b и c существует отношение many to many (используется индекс IDX_ITEMID)

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

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

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)
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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