Левый JOIN быстрее или Inner Join быстрее?
Итак... какой из них быстрее (значение NULl не является проблемой) и индексируется.
SELECT * FROM A
JOIN B b ON b.id = a.id
JOIN C c ON c.id = b.id
WHERE A.id = '12345'
Использование левых соединений:
SELECT * FROM A
LEFT JOIN B ON B.id=A.bid
LEFT JOIN C ON C.id=B.cid
WHERE A.id = '12345'
Вот фактический запрос
Вот он.. оба возвращают тот же результат
Query (0.2693sec) :
EXPLAIN EXTENDED SELECT *
FROM friend_events, zcms_users, user_events,
EVENTS WHERE friend_events.userid = '13006'
AND friend_events.state =0
AND UNIX_TIMESTAMP( friend_events.t ) >=1258923485
AND friend_events.xid = user_events.id
AND user_events.eid = events.eid
AND events.active =1
AND zcms_users.id = user_events.userid
EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE zcms_users ALL PRIMARY NULL NULL NULL 43082
1 SIMPLE user_events ref PRIMARY,eid,userid userid 4 zcms_users.id 1
1 SIMPLE events eq_ref PRIMARY,active PRIMARY4 user_events.eid 1 Using where
1 SIMPLE friend_events eq_ref PRIMARY PRIMARY 8 user_events.id,const 1 Using where
LEFTJOIN QUERY: (0.0393 sec)
EXPLAIN EXTENDED SELECT *
FROM `friend_events`
LEFT JOIN `user_events` ON user_events.id = friend_events.xid
LEFT JOIN `events` ON user_events.eid = events.eid
LEFT JOIN `zcms_users` ON user_events.userid = zcms_users.id
WHERE (
events.active =1
)
AND (
friend_events.userid = '13006'
)
AND (
friend_events.state =0
)
AND (
UNIX_TIMESTAMP( friend_events.t ) >=1258923485
)
EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE friend_events ALL PRIMARY NULL NULL NULL 53113 Using where
1 SIMPLE user_events eq_ref PRIMARY,eid PRIMARY 4 friend_events.xid 1 Using where
1 SIMPLE zcms_users eq_ref PRIMARY PRIMARY 4 user_events.userid 1
1 SIMPLE events eq_ref PRIMARY,active PRIMARY 4 user_events.eid 1 Using where
Ответы
Ответ 1
Это зависит; запустите их обоих, чтобы узнать; затем запустите объяснение для объяснения.
Фактическая разница в производительности может варьироваться от "практически несуществующей" до "довольно значительной" в зависимости от того, сколько строк в с id = '12345' не имеют совпадающих записей в B и C.
Обновить (на основе опубликованных планов запросов)
Когда вы используете INNER JOIN, это не имеет значения (по результатам, а не по производительности), с которой следует начинать таблицу, поэтому оптимизатор пытается выбрать тот, который, по его мнению, будет работать лучше всего. Кажется, у вас есть индексы во всех соответствующих столбцах PK/FK, и у вас либо нет индекса на friend_events.userid
, либо слишком много записей с userid = '13006'
, и оно не используется; в любом случае оптимизатор выбирает таблицу с меньшим количеством строк в качестве "базы" - в этом случае она zcms_users
.
Когда вы используете LEFT JOIN, это делает вопрос (по результатам), с какой таблицы следует начинать; таким образом, friend_events
. Теперь почему это занимает меньше времени, поэтому я не совсем уверен; Я предполагаю, что условие friend_events.userid
помогает. Если бы вы добавили индекс (действительно ли это varchar, btw? Not numeric?), То ваш INNER JOIN может вести себя по-другому (и быстрее).
Ответ 2
INNER JOIN должен выполнить дополнительную проверку, чтобы удалить любые записи из A, которые не имеют соответствующих записей в B и C. В зависимости от количества записей, первоначально возвращенных из A, это МОЖЕТ оказать влияние.
Ответ 3
Используйте EXPLAIN, чтобы увидеть план запроса. Вероятно, это один и тот же план для обоих случаев, поэтому я сомневаюсь, что это имеет большое значение, если нет строк, которые не совпадают. Но это два разных запроса, поэтому на самом деле не имеет смысла сравнивать их - вы должны просто использовать правильный.
Почему бы не использовать ключевое слово "INNER JOIN" вместо "LEFT JOIN"?
Ответ 4
LEFT JOIN
отображает все данные из A
и отображает только данные из B/C
, только если условие истинно. Что касается INNER JOIN
, он должен выполнить некоторую дополнительную проверку как на tables
. Итак, я думаю, это объясняет, почему LEFT JOIN
работает быстрее.