Подзапросы с 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 подзапрос точно знает, что он ищет, и после его обнаружения проверяется условие наличия.