2014-12-19 3 views
3

У меня есть LEFT JOIN, что очень дорого:MySQL создает временную таблицу затем присоединиться быстрее, чем левое соединение

    select X.c1, COUNT(Y.c3) from X LEFT JOIN Y on X.c1=Y.c2 group by X.c1; 

Через несколько минут (20+), он все еще не заканчивается. Но я хочу, чтобы все строки в X. В какой-то момент мне действительно нужен LEFT JOIN.

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

CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS  
(select X.c1 as t, COUNT(Y.c2) as c from X 
INNER JOIN Y where X.c1=Y.c2 group by X.c1); 

select X.c1, table2.c from X  
LEFT JOIN table2 on X.c1 = table2.t;  

Это заканчивается менее чем за две минуты.

Мои вопросы:

1) Являются ли они эквивалентны?

2) Почему второй так быстрее (почему MySQL не делает такую ​​оптимизацию), то есть мне нужно делать эти типы mysql?

EDIT: дополнительная информация: C1, C2 - BIGINTS. C1 уникален, но может быть много C2s, которые все указывают на один и тот же C1. Насколько я знаю, я не индексировал таблицы. X.C1 - это столбец _id, к которому относится Y.c2.

+1

не очень. ваша временная таблица является внутренним соединением, поэтому вы получите результаты, когда записи существовали по обе стороны соединения. левое соединение будет возвращать ВСЕ соответствующие левые записи и ЛЮБЫЕ соответствующие записи справа. –

+0

Но тогда я делаю левое соединение. – Tommy

+0

@MarcB, за исключением просмотра нулей для счетчика, где число равно 0, его второй запрос кажется, что он должен возвращать те же результаты, что и 1-й, потому что он остался присоединенным к таблице temp – FuzzyTree

ответ

3

Попробуйте индексировать X.c1 и Y.c2 и запустить исходный запрос.

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

0

Если x.c1 уникален, то я предложил бы писать запрос как:

select X.c1, 
     (select COUNT(Y.c3) 
     from Y 
     where X.c1 = Y.c2 
     ) 
from X; 

Для этого запроса вы хотите индекс на Y(c2, c3).

Причина, по которой left join может занять больше времени, если много строк не совпадают. В этом случае group by объединяет множество строк, чем это действительно необходимо. И нет, MySQL не пытается такого типа оптимизации.