2009-11-19 1 views
6

У меня есть запрос, как это:Могу ли я заставить mysql сначала выполнить подзапрос?

SELECT `table_1`.* from `table_1` 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE `table_1`.`id` IN(
    SELECT `id` FROM [...] 
) 
AND [more conditions] 

Когда я использую EXPLAIN, есть «DEPENDENT подзапрос» в конце, но я хочу, чтобы это подзапрос будет выполняться первым, раньше других условиях.

Is is?

ответ

2

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

2

Лучший способ - установить условия WHERE для таблицы1 в подзапрос в предложении FROM. EG:

SELECT `table_1`.* 
FROM (
     SELECT * FROM `table_1` WHERE `table_1`.`id` IN (...) 
    ) 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE [more conditions] 
-1

К сожалению, нет, вы не можете. Подзапросы фактически выполняются один раз для каждой строки во внешнем запросе.

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

13
SELECT `table_1`.* 
FROM `table_1` 
INNER JOIN 
     `table_2` [...] 
INNER JOIN 
     `table_3` [...] 
WHERE `table_1`.`id` IN 
     (
     SELECT `id` 
     FROM [...] 
     ) 
     AND [more conditions] 

Если внутренняя таблица правильно проиндексирована, подзапрос здесь не «выполняется» вообще в строгом смысле слова.

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

На самом деле, этот подзапрос оценивается на каждом шаге:

EXISTS 
(
SELECT NULL 
FROM [...] 
WHERE id = table1.id 
) 

Вы можете увидеть его в подробном описании, предоставленной EXPLAIN EXTENDED.

Именно поэтому это называется DEPENDENT SUBQUERY: результат каждой оценки зависит от значения table1.id. Подзапрос как таковой не коррелирован, это коррелированная оптимизированная версия.

MySQL всегда оценивает предложение EXISTS после более простых фильтров (поскольку их намного легче оценить, и существует вероятность того, что подзапрос не будет вообще оцениваться).

Если вы хотите подзапрос, чтобы оценить все сразу, переписать запрос, как это:

SELECT table_1.* 
FROM (
     SELECT DISTINCT id 
     FROM [...] 
     ) q 
JOIN table_1 
ON  table_1.id = q.id 
JOIN table_2 
ON  [...] 
JOIN table_3 
ON  [...] 
WHERE [more conditions] 

Это заставляет подзапрос быть ведущим в соединении, которое является более эффективным, если подзапрос мал по сравнению до table_1 и менее эффективен, если подзапрос является большим по сравнению с table_1.

Если в подзапросе используется индекс [...].id, подзапрос будет выполняться с использованием INDEX FOR GROUP-BY.

+0

Проблема с нажатием подзапроса вниз заключается в том, что это невозможно, если подзапрос зависит от постоянной части внешнего запроса (см. Https://stackoverflow.com/questions/44859809/how-to-optimize-dependent-subquery -with-constant-expression) – andig

3

это известная ошибка в MySQL: http://bugs.mysql.com/bug.php?id=25926

полезным решением является надавите подзапрос в другой select * from (subquery) as dt типа подзапроса.

+0

Указанная ошибка затрагивает только подзапросы 'GROUP BY/DISTINCT'. Предикат 'IN' над подзапросом с предложением' DISTINCT' в нем эквивалентен 'JOIN'. – Quassnoi

+1

нет, проблема также возникает в запросах, которые не связаны с «GROUP BY» или «DISTINCT». опровержение это просто: нажмите подзапрос на другой уровень, как я предлагаю, и посмотрим, изменится ли ЗАВИСИМОЕ ЗАВИСИМОСТЬ в таблицу DERIVED. (и откуда вы знаете, что этот запрос не имеет GROUP BY? исходный плакат не предоставил фактический запрос.) – longneck

+0

Этот метод работы работал для меня: для этого потребовался запрос, который выглядит 32 минуты до 0,452 секунды. Благодаря! – Deebster

 Смежные вопросы

  • Нет связанных вопросов^_^