Подзапросы с EXISTS vs 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
)
)
5 ответов
An Explain Plan
показал бы вам, почему именно вы должны использовать Exists
. Обычно возникает вопрос Exists vs Count(*)
. Exists
быстрее. Почему?
в отношении вызовов, присутствующих NULL: when вложенный запрос возвращает
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
оператор, где I MySQL
Не загружайте результаты.
Как упоминалось в вашем docs ссылка также, что она опускает все, что есть в SELECT
предложения. Он проверяет только первое значение, которое соответствует критериям, после его обнаружения задает условие TRUE
и перемещается для дальнейшей обработки.
С другой стороны, метод 1 имеет IN
оператор, который загружает все возможные значения, а затем сопоставляет его. Условие TRUE
только когда найдено точное совпадение, что является трудоемким процессом.
следовательно, ваш метод 2 быстрый.
надеюсь, что это помогает...
второй метод быстрее, потому что у вас есть это, как там "где t3.reservation_id = Т.reservation_id". В первом случае ваш подзапрос должен выполнить полное сканирование в таблицу для проверки информации. Однако при методе 2o подзапрос точно знает, что он ищет, и как только он найден, проверяется условие наличия.
на оператор логический оператор, который возвращает true или false. Оператор EXISTS часто используется в подзапрос для проверки на "exist" состояние.
SELECT
select_list
FROM
a_table
WHERE
[NOT] EXISTS(subquery);
Если подзапрос возвращает все строки оператор возвращает true, иначе возвращает false.
кроме того, оператор немедленно завершает дальнейшую обработку, как только находит соответствующую строку. Из-за этой характеристики вы можете использовать оператор для повышения производительности запроса в некоторых случаях.
на не оператор перечеркивает оператора. Другими словами,НЕ СУЩЕСТВУЕТ возвращает true, если подзапрос не возвращает строку, в противном случае он возвращает false.
можно использовать выберите *, выберите столбец, выберите a_constant, или что-нибудь в подзапрос. Результаты одинаковы, потому что MySQL игнорирует select_list в инструкции это появляется в выберите предложения.
причина в том, что оператор работает на основе принципа" по крайней мере, найдено". Он возвращает true и останавливает сканирование таблицы один раз, по крайней мере, одна соответствующая строка найдена.
С другой стороны, когда на оператор объединяется с подзапросом, MySQL должен сначала обработать подзапрос, а затем использует результат подзапроса для обработки всего запроса.
общее правило большого пальца заключается в том, что если подзапрос содержит большой объем данных оператор обеспечивает лучшую производительность.
однако запрос, который использует на оператор будет работать быстрее, если результирующий набор, возвращаемый подзапросом очень мало.
для подробных объяснений и примеров: MySQL существует - mysqltutorial.org