Подзапросы с EXISTS против IN - MySQL
Ниже два запроса являются подзапросами. Оба одинаковы, и оба работают отлично для меня. Но проблема в том, что запрос метода 1 занимает около 10 секунд для выполнения, в то время как запрос метода 2 занимает менее 1 секунды.
Мне удалось преобразовать запрос метода 1 в метод 2, но я не понимаю, что происходит в запросе. Я пытался понять это сам. Я бы очень хотел узнать, какая разница между двумя запросами и как происходит увеличение производительности? какова его логика?
Я новичок в этих методах продвижения. Надеюсь, кто-то поможет мне здесь. Учитывая, что я прочитал docs, который не дает мне подсказки.
Способ 1:
SELECT
*
FROM
tracker
WHERE
reservation_id IN (
SELECT
reservation_id
FROM
tracker
GROUP BY
reservation_id
HAVING
(
method = 1
AND type = 0
AND Count(*) > 1
)
OR (
method = 1
AND type = 1
AND Count(*) > 1
)
OR (
method = 2
AND type = 2
AND Count(*) > 0
)
OR (
method = 3
AND type = 0
AND Count(*) > 0
)
OR (
method = 3
AND type = 1
AND Count(*) > 1
)
OR (
method = 3
AND type = 3
AND Count(*) > 0
)
)
Способ 2:
SELECT
*
FROM
`tracker` t
WHERE
EXISTS (
SELECT
reservation_id
FROM
`tracker` t3
WHERE
t3.reservation_id = t.reservation_id
GROUP BY
reservation_id
HAVING
(
METHOD = 1
AND TYPE = 0
AND COUNT(*) > 1
)
OR
(
METHOD = 1
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 2
AND TYPE = 2
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 0
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 3
AND TYPE = 3
AND COUNT(*) > 0
)
)
Ответы
Ответ 1
Explain Plan
показал бы, почему именно вы должны использовать Exists
. Обычно возникает вопрос Exists vs Count(*)
. Exists
быстрее. Почему?
-
Что касается проблем, возникающих в NULL: когда возвращает подзапрос Null
, для IN весь запрос становится Null
. Поэтому вам тоже нужно это обработать. Но используя Exist
, он просто a false
. Намного легче справиться. Просто IN
не может сравнивать ничего с Null
, но Exists
может.
-
например. Exists (Select * from yourtable where bla = 'blabla');
вы получите true/false момент один удар найден/сопоставлен.
-
В этом случае IN
тип принимает позицию Count(*)
для выбора ВСЕ совпадающих строк на основе WHERE
, потому что он сравнивает все значения.
Но не забывайте и об этом:
-
Exists
выполняется с высокой скоростью по сравнению с IN
: когда результаты подзапроса очень велики.
-
IN
опережает Exists
: когда результаты подзапроса очень малы.
Ссылка на дополнительную информацию:
Ответ 2
Метод 2 выполняется быстро, потому что он использует оператор EXISTS
, где я MySQL
не загружает никаких результатов.
Как уже упоминалось в вашей docs, он опускает все, что есть в SELECT
. Он проверяет только первое значение, соответствующее критериям, после того как оно установлено, оно устанавливает условие TRUE
и перемещается для дальнейшей обработки.
С другой стороны, метод 1 имеет оператор IN
, который загружает все возможные значения и затем сопоставляет его. Условие установлено TRUE
только при обнаружении точного соответствия, которое требует много времени.
Следовательно, ваш метод 2 быстр.
Надеюсь, что это поможет...
Ответ 3
Второй метод быстрее, потому что у вас есть это как "WHERE t3.reservation_id = t.reservation_id". В первом случае ваш подзапрос должен выполнить полное сканирование в таблицу, чтобы проверить информацию. Однако в методе 2o подзапрос точно знает, что он ищет, и после его обнаружения проверяется условие наличия.
Ответ 4
Официальная документация Оптимизация SubQuery с Exists