it-roy-ru.com

Подзапросы с EXISTS vs IN - 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
         )                                             
   )
20
Techie

Explain Plan показал бы, почему именно вы должны использовать Exists. Обычно вопрос приходит Exists vs Count(*). Exists быстрее. Зачем?

  • Что касается проблем, представленных NULL: когда подзапрос возвращает Null, для IN весь запрос становится Null. Таким образом, вы должны справиться с этим также. Но используя Exist, это просто false. Намного легче справиться. Просто IN ничего не может сравнить с Null, но Exists может.

  • например Exists (Select * from yourtable where bla = 'blabla'); вы получаете истину/ложь в тот момент, когда один удар найден/соответствует

  • В этом случае IN сортирует позицию Count(*), чтобы выбрать ВСЕ соответствующие строки на основе WHERE, потому что он сравнивает все значения. 

Но не забывайте и об этом:

  • EXISTS выполняется с высокой скоростью по сравнению с IN: когда результаты подзапроса очень велики.
  • IN опережает EXISTS: когда результаты подзапроса очень малы.

Ссылка на более подробную информацию:

46
bonCodigo

Метод 2 быстрый, потому что он использует оператор EXISTS, где я MySQL не загружаю никаких результатов . Как уже упоминалось в вашей ссылке docs , он опускает все, что есть в предложении SELECT. Он проверяет только первое значение, которое соответствует критериям, после того, как он найден, он устанавливает условие TRUE и перемещается для дальнейшей обработки. 

С другой стороны, у метода 1 есть оператор IN, который загружает все возможные значения и затем сопоставляет его. Условие устанавливается TRUE только тогда, когда найдено точное соответствие, которое занимает много времени.

Следовательно, ваш метод 2 быстрый.

Надеюсь, поможет... 

3
Shubhansh

Оператор СУЩЕСТВУЮЩИЕ является логическим оператором, который возвращает либо true, либо false. Оператор EXISTS часто используется в подзапрос для проверки условия «существует».

SELECT 
    select_list
FROM
    a_table
WHERE
    [NOT] EXISTS(subquery);

Если подзапрос возвращает какую-либо строку, оператор EXIST возвращает true, в противном случае он возвращает false.

Кроме того, оператор СУЩЕСТВУЮЩИЕ прекращает дальнейшую обработку немедленно, как только находит соответствующую строку. Из-за этой характеристики вы можете использовать оператор СУЩЕСТВУЮЩИЕ, чтобы повысить производительность запроса в некоторых случаях.

Оператор NOT отменяет оператор СУЩЕСТВУЮЩИЕ. Другими словами, NOT EXISTS возвращает true, если подзапрос не возвращает строки, в противном случае он возвращает false.

Вы можете использовать SELECT *, SELECT столбец, SELECT a_constant или что-нибудь в подзапросе. Результаты совпадают, потому что MySQL игнорирует select_list, который появляется в предложении SELECT.

Причина в том, что оператор СУЩЕСТВУЮЩИЕ работает по принципу «по крайней мере найден». Возвращает true и останавливает сканирование таблицы, если найдена хотя бы одна подходящая строка.

С другой стороны, когда оператор IN объединяется с подзапросом, MySQL должен сначала обработать подзапрос, а затем использовать результат подзапроса для обработки всего запроса.

Общее правило заключается в том, что если подзапрос содержит большой объем данных, оператор СУЩЕСТВУЮЩИЕ обеспечивает более высокую производительность.

Однако запрос, использующий оператор IN, будет выполняться быстрее, если набор результатов, возвращаемый из подзапроса, очень мал.

Для подробных объяснений и примеров: MySQL EXISTS - mysqltutorial.org

1
ktnam

Второй метод быстрее, потому что у вас есть это как "где t3.reservation_id = t.reservation_id". В первом случае ваш подзапрос должен выполнить полное сканирование таблицы, чтобы проверить информацию. Однако в методе 20o подзапрос точно знает, что он ищет, и как только он найден, проверяется условие наличия. 

0
medina