Разница между EXISTS и IN в SQL?


443

В чем разница между EXISTSи INпунктом в SQL?

Когда мы должны использовать EXISTS, и когда мы должны использовать IN?

Ответы:


224

existsКлючевое слово может быть использовано таким образом, но на самом деле он предназначен как способ подсчета следует избегать:

--this statement needs to check the entire table
select count(*) from [table] where ...

--this statement is true as soon as one match is found
exists ( select * from [table] where ... )

Это наиболее полезно, когда у вас есть ifусловные операторы, так как это existsможет быть намного быстрее, чем count.

inЛучше всего использовать , когда у вас есть список статического пройти:

 select * from [table]
 where [field] in (1, 2, 3)

Когда у вас есть таблица в inутверждении, имеет смысл использовать a join, но в основном это не должно иметь значения. Оптимизатор запросов должен возвращать тот же план в любом случае. В некоторых реализациях (в основном старых, таких как Microsoft SQL Server 2000) inзапросы всегда получают вложенный план соединения , тогда как joinзапросы будут использовать вложенные, слияния или хэширования в зависимости от ситуации. Более современные реализации умнее и могут корректировать план даже при inиспользовании.


2
Не могли бы вы пояснить: «Когда у вас есть таблица в операторе in, имеет смысл использовать объединение, но это не имеет значения. Оптимизатор запросов в любом случае вернет тот же план».? Не часть оптимизатора запросов, а часть, где вы можете использовать JOINее вместо IN.
farthVader

select * from [table] where [field] in (select [field] from [table2])возвращает те же результаты (и план запроса), что и select * from [table] join [table2] on [table2].[field] = [table].[field].

@ Сандер это не делает: первый запрос возвращает все столбцы из table, а второй возвращает все из tableи table2. В некоторых (в основном старых) базах данных SQL inзапрос будет реализован как вложенное объединение, в то время как joinзапрос может быть вложенным, объединенным, хэшированным и т. Д. - как угодно быстро.
Кит

2
Хорошо, я должен был указать столбцы в предложении select, но вы должны обновить свой ответ, поскольку в нем четко указано, что запросы «в любом случае будут возвращать один и тот же план».

existsможет использоваться внутри оператора case, поэтому они могут быть полезны и в этом случае, например:select case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie

126

EXISTSскажет вам, вернул ли запрос какие-либо результаты. например:

SELECT * 
FROM Orders o 
WHERE EXISTS (
    SELECT * 
    FROM Products p 
    WHERE p.ProductNumber = o.ProductNumber)

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

SELECT * 
FROM Orders 
WHERE ProductNumber IN (1, 10, 100)

Вы также можете использовать результаты запроса с INпредложением, например так:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)

3
Последний запрос опасен, потому что он может потерпеть неудачу в том случае, если подзапрос не возвращает никаких результатов. предложение 'in' требует как минимум 1 аргумент ...
user2054927

41
@ user2054927 Последний запрос не будет возвращать ни одной строки, если подзапрос не возвращает ни одной строки - в этом нет ничего опасного!
Тони Эндрюс

Лучший ответ.
Аминадав Гликштайн

81

На основе правила оптимизатора :

  • EXISTSгораздо быстрее, чем IN, когда результаты подзапроса очень велики.
  • INбыстрее, чем EXISTS, когда результаты подзапроса очень малы.

На основе оптимизатора затрат :

  • Нет никакой разницы.

21
Доказательство вашего аргумента? Я не думаю, что IN будет быстрее, чем EXISTS!
Наваз

22
@Nawaz Как насчет доказательства, почему IN всегда медленнее, чем EXISTS?
выступление

2
Плохо реализован оптимизатор запросов? Кажется, что-то подобное (хотя и не совсем в такой ситуации) происходит в определенных RDBM ...
Haroldo_OK

1
EXISTS возвращает чисто логические значения, что всегда быстрее, чем сравнивать строки или значения больше, чем тип BIT / Boolean. IN может или не может быть логическим сравнением. Поскольку программирование предпочитает использовать EXPLICIT для стабильности (часть ACID), EXISTS обычно предпочтительнее.
clifton_h

2
Почему за это проголосовали так много раз? Нет абсолютно никакой причины, почему это основанное на предположениях утверждение должно быть в целом верным.
Лукас Эдер

40

Я предполагаю, что вы знаете, что они делают, и, таким образом, они используются по-разному, поэтому я пойму ваш вопрос следующим образом: когда будет хорошей идеей переписать SQL-код, чтобы использовать IN вместо EXISTS, или наоборот.

Это справедливое предположение?


Редактировать : причина, по которой я спрашиваю, состоит в том, что во многих случаях вы можете переписать SQL на основе IN, чтобы использовать вместо него EXISTS, и наоборот, и для некоторых механизмов баз данных оптимизатор запросов будет обрабатывать их по-разному.

Например:

SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

можно переписать на:

SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

или с объединением:

SELECT Customers.*
FROM Customers
    INNER JOIN Orders ON Customers.ID = Orders.CustomerID

Таким образом, мой вопрос все еще остается в силе: интересно ли оригинальному постеру узнать о том, что делает IN и EXISTS, и, следовательно, как его использовать, или он попросит переписать SQL-запрос с использованием IN, чтобы вместо него использовать EXISTS, или наоборот, будет хорошей идеей?


12
Я не знаю об ОП, но мне хотелось бы получить ответ на этот вопрос! Когда я должен использовать EXISTS вместо IN с подзапросом, который возвращает идентификаторы?
Рой Тинкер

8
в JOIN, вам понадобитсяDISTINCT
Jaider

4
отличная демонстрация, но в значительной степени оставьте вопрос без ответа
Junchen Liu

28
  1. EXISTSгораздо быстрее, чем INкогда результаты подзапроса очень велики.
    INбыстрее, чем EXISTSкогда результаты подзапроса очень малы.

    CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
    GO
    CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
    GO
    
    INSERT INTO t1
    SELECT 1, 'title 1', 5 UNION ALL
    SELECT 2, 'title 2', 5 UNION ALL
    SELECT 3, 'title 3', 5 UNION ALL
    SELECT 4, 'title 4', 5 UNION ALL
    SELECT null, 'title 5', 5 UNION ALL
    SELECT null, 'title 6', 5
    
    INSERT INTO t2
    SELECT 1, 1, 'data 1' UNION ALL
    SELECT 2, 1, 'data 2' UNION ALL
    SELECT 3, 2, 'data 3' UNION ALL
    SELECT 4, 3, 'data 4' UNION ALL
    SELECT 5, 3, 'data 5' UNION ALL
    SELECT 6, 3, 'data 6' UNION ALL
    SELECT 7, 4, 'data 7' UNION ALL
    SELECT 8, null, 'data 8' UNION ALL
    SELECT 9, 6, 'data 9' UNION ALL
    SELECT 10, 6, 'data 10' UNION ALL
    SELECT 11, 8, 'data 11'
    
  2. Запрос 1

    SELECT
    FROM    t1 
    WHERE   not  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)
    

    Запрос 2

    SELECT t1.* 
    FROM   t1 
    WHERE  t1.id not in (SELECT  t2.t1id FROM t2 )
    

    Если в t1вашем id есть нулевое значение, тогда Query 1 найдет их, но Query 2 не может найти нулевые параметры.

    Я имею в виду, что INничего нельзя сравнить с нулем, поэтому он не имеет результата для нуля, но EXISTSможет сравнить все с нулем.


Этот ответ является разумным кратким изложением настроений Тома Кайта ( asktom.oracle.com/pls/asktom/… )
Джером Френч

Я думаю, что этот ответ основан на интуиции, что достаточно справедливо. Но это не может быть универсально правдой. Например, почти наверняка это не так с Ingres , который будет анализировать оба эквивалентных SQL-запроса как один и тот же QUEL-запрос, которому не хватает «богатства» SQL, когда речь идет о написании одной и той же вещи несколькими способами.
когда

Эти 2 запроса логически эквивалентны, если и только если t2.id определен как «NOT NULL». Чтобы получить эквивалентность без зависимости в определении таблицы, 2-й запрос должен быть «ВЫБРАТЬ t1. * ОТ t1, ГДЕ t1.id не в (ВЫБРАТЬ t2.id ОТ t2, где t2.id не нуль
Дэвид דודו Марковиц

16

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


10

IN поддерживает только отношения равенства (или неравенства, когда им предшествует NOT ).
Это синоним = любой / = некоторые , например,

select    * 
from      t1 
where     x in (select x from t2)
;

EXISTS поддерживает разные типы отношений, которые нельзя выразить с помощью IN , например:

select    * 
from      t1 
where     exists (select    null 
                  from      t2 
                  where     t2.x=t1.x 
                        and t2.y>t1.y 
                        and t2.z like '℅' || t1.z || '℅'
                  )
;

И на другой ноте -

Предполагаемая производительность и технические различия между EXISTS и IN могут быть результатом реализаций / ограничений / ошибок конкретного поставщика, но во многих случаях они являются не более чем мифами, созданными из-за непонимания внутренних структур баз данных.

Определение таблиц, точность статистики, конфигурация базы данных и версия оптимизатора оказывают влияние на план выполнения и, следовательно, на показатели производительности.


Upvote за ваш комментарий о производительности: не сосредотачиваясь на конкретной СУБД, мы должны предположить, что оптимизатор должен решить, что работает лучше всего.
Manngo

9

ExistsКлючевое слово оценивает истинным или ложным, но INключевое слово сравнить все значения в соответствующем столбце юга запроса. Еще один Select 1можно использовать с Existsкомандой. Пример:

SELECT * FROM Temp1 where exists(select 1 from Temp2 where conditions...)

Но INменее эффективно, так Existsбыстрее.


5

Я думаю,

  • EXISTSэто когда вам нужно сопоставить результаты запроса с другим подзапросом. Результаты запроса # 1 должны быть получены там, где совпадают результаты SubQuery. Вид присоединения. Например, таблица клиентов № 1, которые также разместили таблицу заказов № 2

  • IN предназначен для извлечения, если значение определенного столбца находится INв списке (1,2,3,4,5). Например, выберите клиентов, которые находятся в следующих почтовых индексах, т.е. значения zip_code находятся в (....) списке.

Когда использовать один поверх другого ... когда вы чувствуете, что он читается соответствующим образом (лучше информирует о намерениях).


4

Разница заключается здесь:

select * 
from abcTable
where exists (select null)

Выше запрос вернет все записи, а ниже один вернется пустым.

select *
from abcTable
where abcTable_ID in (select null)

Попробуйте и посмотрите на результат.


1
Хммм ... Ошибка: [SQL0104] Token) был недействителен. В обоих случаях. Вы предполагаете конкретную СУРБД?
jmarkmurphy

3

Насколько я знаю, когда подзапрос возвращает NULLзначение, тогда весь оператор становится NULL. В этих случаях мы используем EXITSключевое слово. Если мы хотим сравнить конкретные значения в подзапросах, мы используем INключевое слово.


3

Какой из них быстрее, зависит от количества запросов, извлекаемых внутренним запросом:

  • Когда ваш внутренний запрос извлекает тысячи строк, тогда EXIST будет лучшим выбором.
  • Когда ваш внутренний запрос извлекает несколько строк, IN будет быстрее

EXIST оценивает на true или false, но IN сравнивает множественное значение. Если вы не знаете, существует запись или нет, вы должны выбрать EXIST


3

Причина в том, что оператор EXISTS работает по принципу «как минимум найден». Возвращает true и останавливает сканирование таблицы, если найдена хотя бы одна подходящая строка.

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

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

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


1

Я понимаю, что оба должны быть одинаковыми, если мы не имеем дело со значениями NULL.

По той же причине, по которой запрос не возвращает значение для = NULL против NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

Что касается аргумента «булево против компаратора», то для генерации логического значения необходимо сравнить оба значения, и вот как работает любое условие. Поэтому я не могу понять, как IN и EXISTS ведут себя по-разному.



0

Если подзапрос возвращает более одного значения, вам может потребоваться выполнить внешний запрос - если значения в столбце, указанном в условии, соответствуют какому-либо значению в наборе результатов подзапроса. Для выполнения этой задачи вам необходимо использовать inключевое слово.

Вы можете использовать подзапрос, чтобы проверить, существует ли набор записей. Для этого вам нужно использовать existsпредложение с подзапросом. existsКлючевое слово всегда возвращает истинное или ложное значение.


0

Я считаю, что это имеет прямой ответ. Почему бы вам не проверить это у людей, которые разработали эту функцию в своих системах?

Если вы являетесь разработчиком MS SQL, вот ответ непосредственно от Microsoft.

IN:

Определяет, соответствует ли указанное значение какому-либо значению в подзапросе или списке.

EXISTS:

Определяет подзапрос для проверки существования строк.



-1

EXISTS быстрее в производительности, чем IN. Если большинство критериев фильтра находится в подзапросе, то лучше использовать IN, а если большинство критериев фильтра находится в основном запросе, то лучше использовать EXISTS.


Это утверждение на самом деле не подкреплено какими-либо доказательствами, не так ли?
Лукас Эдер

-2

Если вы используете оператор IN, механизм SQL будет сканировать все записи, извлеченные из внутреннего запроса. С другой стороны, если мы используем EXISTS, механизм SQL остановит процесс сканирования, как только найдет совпадение.


@ Зигги, объясни? Это в значительной степени то, что говорит принятый ответ. При ОБЯЗАТЕЛЬНО проверять каждую отдельную запись, существование может прекратиться, как только найдет только одну.
Бен Терли

Нет, не правильно. INи EXISTSможет быть эквивалентным и преобразованным друг в друга.
Лукас Эдер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.