Подзапросы с 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
         )                                             
   )
Author: bonCodigo, 2013-01-07

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: когда результат подзапроса очень мал.

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

 41
Author: bonCodigo, 2017-05-23 12:10:12

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

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

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

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

 3
Author: Shubhansh, 2013-01-07 06:14:40

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

 0
Author: medina, 2013-01-07 07:36:00

Оператор СУЩЕСТВУЕТ - это логический оператор, который возвращает значение 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

 0
Author: ktnam, 2018-09-20 08:04:37
 -2
Author: kta, 2014-04-15 14:12:23