Подзапросы с EXISTS vs В MySQL
Ниже два запроса являются подзапросами. Оба они одинаковы, и оба отлично работают для меня. Но проблема в том, что выполнение запроса метода 1 занимает около 10 секунд, в то время как запрос метода 2 занимает менее 1 секунды.
Мне удалось преобразовать запрос метода 1 в метод 2, но я не понимаю, что происходит в запросе. Я и сам пытался в этом разобраться. Мне бы очень хотелось узнать, в чем разница между приведенными ниже двумя запросами и как происходит увеличение производительности? в чем логика за этим?
Я новичок в этих передовых методах. Я надеюсь, что кто-нибудь поможет мне здесь. Учитывая, что я прочитал документы, которые не дают мне ключа к разгадке.
Метод 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
)
)
5 answers
Ан Explain Plan
показал бы вам, почему именно вы должны использовать Exists
. Обычно возникает вопрос Exists vs Count(*)
. Exists
быстрее. Почему?
Что касается проблем, связанных с NULL: когда подзапрос возвращает
Null
, для всего запроса становитсяNull
. Так что тебе тоже нужно с этим справиться. Но используяExist
, это простоfalse
. Гораздо легче справиться. ПростоIN
не может ничего сравнить сNull
, ноExists
может.Например.
Exists (Select * from yourtable where bla = 'blabla');
вы получаете значение true/false в тот момент, когда найдено/сопоставлено одно попадание.В этом случае
IN
как бы занимает позициюCount(*)
для выбора ВСЕХ совпадающих строк на основеWHERE
, потому что он сравнивает все значения.
Но не забывайте и об этом:
-
EXISTS
выполняется с высокой скоростью по сравнению сIN
: когда результаты подзапроса очень велики. -
IN
опережаетEXISTS
: когда результат подзапроса очень мал.
Ссылка для получения более подробной информации:
Метод 2 быстр, потому что он использует оператор EXISTS
, где я MySQL
не загружаю никаких результатов.
Как уже упоминалось в вашей ссылке docs, она также опускает все, что есть в предложении SELECT
. Он проверяет только первое значение, соответствующее критериям, после его нахождения устанавливает условие TRUE
и перемещается для дальнейшей обработки.
С другой стороны, метод 1 имеет оператор IN
, который загружает все возможные значения, а затем сопоставляет их. Условие устанавливается TRUE
только тогда, когда точное совпадение найдено, что является трудоемким процессом.
Следовательно, ваш метод 2 быстр.
Надеюсь, это поможет...
Второй метод быстрее, потому что у вас есть это, как там "ГДЕ t3.reservation_id = t.reservation_id". В первом случае ваш подзапрос должен выполнить полное сканирование таблицы для проверки информации. Однако в методе 2o подзапрос точно знает, что он ищет, и как только он найден, проверяется условие наличия.
Оператор СУЩЕСТВУЕТ - это логический оператор, который возвращает значение true или false. Оператор EXISTS часто используется в подзапросе для проверки условия "существует".
SELECT
select_list
FROM
a_table
WHERE
[NOT] EXISTS(subquery);
Если подзапрос возвращает любую строку, оператор СУЩЕСТВУЕТ возвращает true, в противном случае он возвращает false.
Кроме того, оператор СУЩЕСТВУЕТ немедленно завершает дальнейшую обработку, как только находит соответствующую строку. Благодаря этой характеристике вы можете использовать оператор СУЩЕСТВУЕТ для повышения производительности запроса в некоторых случаях.
Оператор НЕ отрицает оператор СУЩЕСТВУЕТ . Другими словами, НЕ СУЩЕСТВУЕТ возвращает true, если подзапрос не возвращает строки, в противном случае он возвращает false.
Вы можете использовать ВЫБРАТЬ *, ВЫБЕРИТЕ столбец, ВЫБЕРИТЕ a_constant или что-нибудь в подзапросе. Результаты те же, потому что MySQL игнорирует список выбора, который появляется в ВЫБЕРИТЕ предложение.
Причина в том, что оператор СУЩЕСТВУЕТ работает по принципу "по крайней мере, найден". Он возвращает значение true и прекращает сканирование таблицы, как только найдена хотя бы одна совпадающая строка.
С другой стороны, когда оператор В объединяется с подзапросом, MySQL должен сначала обработать подзапрос, а затем использовать результат подзапроса для обработки всего запроса.
Общее эмпирическое правило заключается в том, что если подзапрос содержит большой объем данные, оператор СУЩЕСТВУЕТ обеспечивает лучшую производительность.
Однако запрос, использующий оператор В , будет выполняться быстрее, если результирующий набор, возвращаемый из подзапроса, очень мал.
Для подробных объяснений и примеров: MySQL СУЩЕСТВУЕТ - mysqltutorial.org
Их Официальная Документация. Оптимизация подзапросов с помощью существующих