복붙노트

[SQL] NOT NOT이있는 대 IN

SQL

NOT NOT이있는 대 IN

빠른 이러한 쿼리의 무엇입니까?

NOT EXISTS :

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE NOT EXISTS (
    SELECT 1 
    FROM Northwind..[Order Details] od 
    WHERE p.ProductId = od.ProductId)

또는 NOT IN :

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
    SELECT ProductID 
    FROM Northwind..[Order Details])

쿼리 실행 계획은 모두 같은 일을 말한다. 그 경우, 권장 형태 인 경우?

이는에서는 Northwind 데이터베이스를 기반으로합니다.

[편집하다]

그냥이 도움이 기사를 발견 : http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

나는 NOT 존재와 내가 스틱 것 같아요.

해결법

  1. ==============================

    1.NOT 존재에 나는 항상 기본.

    NOT 존재에 나는 항상 기본.

    실행 계획은 순간에 동일하지만 수도 있고 열이 NULL을 허용하도록 앞으로 변경되는 경우 NOT (더 NULL을 실제 데이터에 존재하지 않는 경우에도) 더 많은 작업을 수행해야합니다 버전 및 NOT IN의 의미 IN 널 (NULL)이있는 경우에는 당신이 어쨌든 원하는 사람이 될 가능성이 있습니다.

    Products.ProductID 또는 [주문 정보] .ProductID이 모두 널 (null)을 허용 할 때 NOT IN은 다음 쿼리와 동일하게 취급됩니다.

    SELECT ProductID,
           ProductName
    FROM   Products p
    WHERE  NOT EXISTS (SELECT *
                       FROM   [Order Details] od
                       WHERE  p.ProductId = od.ProductId) 
    

    정확한 계획은 다를 수 있지만, 내 예를 들어, 데이터 I는 다음을 얻는다.

    합리적으로 일반적인 오해는 상관 서브 쿼리 조인에 비해 항상 "나쁜"것으로 보인다. 그들은 (행에 의해 서브 쿼리 평가를 행) 중첩 루프 계획을 강제로 할 때 그들은 확실히 할 수 있지만이 계획은 반 반이 논리 연산자에 가입이 포함되어 있습니다. 안티 세미 중첩 루프에 제한되지 조인하지만 너무 조인 (이 예에서와 같이) 해시 또는 병합을 사용할 수 있습니다.

    /*Not valid syntax but better reflects the plan*/ 
    SELECT p.ProductID,
           p.ProductName
    FROM   Products p
           LEFT ANTI SEMI JOIN [Order Details] od
             ON p.ProductId = od.ProductId 
    

    [주문 정보] .ProductID이 NULL-수있는 경우 쿼리는된다

    SELECT ProductID,
           ProductName
    FROM   Products p
    WHERE  NOT EXISTS (SELECT *
                       FROM   [Order Details] od
                       WHERE  p.ProductId = od.ProductId)
           AND NOT EXISTS (SELECT *
                           FROM   [Order Details]
                           WHERE  ProductId IS NULL) 
    

    그 이유는 [주문 정보]를 어떤 NULL의 ProductIds 포함 된 경우 정확한 의미는 결과가 없다고하는 것입니다. 여분의 반 반이 가입하고 행 수 스풀 계획에 추가됩니다이를 확인하기를 참조하십시오.

    Products.ProductID는 NULL-수있게되고 변경되는 경우 쿼리는된다

    SELECT ProductID,
           ProductName
    FROM   Products p
    WHERE  NOT EXISTS (SELECT *
                       FROM   [Order Details] od
                       WHERE  p.ProductId = od.ProductId)
           AND NOT EXISTS (SELECT *
                           FROM   [Order Details]
                           WHERE  ProductId IS NULL)
           AND NOT EXISTS (SELECT *
                           FROM   (SELECT TOP 1 *
                                   FROM   [Order Details]) S
                           WHERE  p.ProductID IS NULL) 
    

    그 하나의 이유는 NULL Products.ProductId가 결과에 반환되지 않아야하기 때문이다 NOT 서브 쿼리가 (즉, [주문 정보] 테이블이 비어) 전혀 결과를 반환하지 것 인 경우를 제외하고. 에있는이해야하는 경우. 내 샘플 데이터에 대한 계획이 다른 반 반은 아래에 가입 추가하여 구현된다.

    이것의 효과는 이미 버클리에 의해 링크 된 블로그 게시물에 표시됩니다. 예에서 논리의 수는 약 400에서 50로 증가가 읽습니다.

    하나의 NULL 0으로 행 수를 줄일 수 있다는 것을 또한 사실은 카디널리티 추정이 매우 어려워집니다. SQL Server는이 더 큰 쿼리의 한 부분 인 경우이 고가의 반복 실행을 일으키는 원인이 부적절 중첩 루프와 함께,하지만 실제로 실행 계획의 나머지 부분은 격변 적으로 악화 될 수있는 데이터에는 NULL 열이 존재하지 일어날 것으로 가정하면 예를 들어 하위 트리.

    이것은 그러나 NULL-수 컬럼에 NOT IN에 대한 유일하게 가능한 실행 계획이 아니다. 이 문서의 표시 AdventureWorks2008 데이터베이스에 대해 쿼리에 대한 또 다른 하나.

    NOT IN 대한 NOT NULL 열 또는 NOT 것은 다음과 같은 계획을 제공하는 널 (NULL) 또는 비 널 (NULL) 열 중 하나에 존재한다.

    열이 NULL-수 NOT IN 계획이 지금처럼 보인다으로 변경하는 경우

    그것은 여분의 내부는 계획에 조인 연산자를 추가합니다. 이 장치는 여기에 설명된다. 그것은 이전의 하나의 상관 지수가 변환하는 모든이에 Sales.SalesOrderDetail.ProductID = 에서 추구이다 외부 행 당 추구한다. 추가 한 Sales.SalesOrderDetail.ProductID NULL이되는 위치에있다.

    반 반 가입에 따라 본이기 때문에 하나 개를 반환하는 경우 두 번째이 찾는 모든 행이 발생하지 않습니다. Sales.SalesOrderDetail 어떤 NULL의 ProductIDs를 포함하지 않는 그러나 경우 필요 찾는 작업의 수를 두 배로.

  2. ==============================

    2.또한 NOT IN이가 null에 관해서 만 존재하는 일치하지 않는 점에 유의.

    또한 NOT IN이가 null에 관해서 만 존재하는 일치하지 않는 점에 유의.

    이 게시물이 아주 잘 설명

    http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

  3. ==============================

    3.실행 계획들이 같은 것 말한다면, 그들은 같은 것. 이 경우, 두 번째에 - 하나는 당신의 의도가 더 분명 할 것 중 사용.

    실행 계획들이 같은 것 말한다면, 그들은 같은 것. 이 경우, 두 번째에 - 하나는 당신의 의도가 더 분명 할 것 중 사용.

  4. ==============================

    4.사실, 나는 이것이 가장 빠른 것 생각 :

    사실, 나는 이것이 가장 빠른 것 생각 :

    SELECT ProductID, ProductName 
        FROM Northwind..Products p  
              outer join Northwind..[Order Details] od on p.ProductId = od.ProductId)
    WHERE od.ProductId is null
    
  5. ==============================

    5.난 단지 행 약 1500, 4000, 40000의 수를 4 개 개의 다른 테이블에 (A VARCHAR 컬럼과 일치)이 존재하지 않는 사람을 선택 120,000 기록과 필요성이있는 테이블이, (200) 모든 관련 테이블은 고유 인덱스를 해당 의료 VARCHAR C 럼에.

    난 단지 행 약 1500, 4000, 40000의 수를 4 개 개의 다른 테이블에 (A VARCHAR 컬럼과 일치)이 존재하지 않는 사람을 선택 120,000 기록과 필요성이있는 테이블이, (200) 모든 관련 테이블은 고유 인덱스를 해당 의료 VARCHAR C 럼에.

    NOT IN이 NOT 4 초 걸렸다 존재하며, 10 분 걸렸다.

    나는 10 분에 기여 수있는 몇 가지 조정되지 않은 부분을 가지고 있습니다 재귀 쿼리를 가지고 있지만, 4 초를 복용 다른 옵션은 NOT 훨씬 더 나은 또는 적어도 점에서이다 존재하고 존재하는 나에게이어야, 설명 정확히 동일하지 않습니다 항상 가치가 체크 코드로 앞서 가기 전에.

  6. ==============================

    6.최적화가 무엇을 당신이하려고하는 것은 두 예에서 동일 파악했기 때문에 특정 예에서 그들은 동일합니다. 그러나 비 사소한 예에 최적화이 작업을 수행하지 않을 수 가능하며,이 경우에 경우에 다른 하나를 선호하는 이유가있다.

    최적화가 무엇을 당신이하려고하는 것은 두 예에서 동일 파악했기 때문에 특정 예에서 그들은 동일합니다. 그러나 비 사소한 예에 최적화이 작업을 수행하지 않을 수 가능하며,이 경우에 경우에 다른 하나를 선호하는 이유가있다.

    당신이 당신의 외부 선택에서 여러 행을 테스트하는 경우가 바람직해야하지. NOT IN 문 내부의 서브 쿼리는 실행의 시작 부분에 평가 될 수 있으며, 임시 테이블보다는, 외부 선택에 각 값에 대해 확인할 수 있습니다 재 실행이 NOT 문을 존재합니다 요구하는대로 부속 때마다 .

    부질가 외부 선택과 상관되어야한다면, NOT 최적화는 동일한 기능을 수행하기 위해 임시 테이블의 생성을 방지하는 단순화를 발견 할 수 있기 때문에, 바람직 할 수있다 존재한다.

  7. ==============================

    7.내가 사용하고 있었다

    내가 사용하고 있었다

    SELECT * from TABLE1 WHERE Col1 NOT IN (SELECT Col1 FROM TABLE2)
    

    그것은 잘못된 결과를 제공하는 것을 발견 (잘못하여 나는 결과가 의미 없음). 로 TABLE2.Col1에 NULL이 있었다.

    에 대한 쿼리를 변경하는 동안

    SELECT * from TABLE1 T1 WHERE NOT EXISTS (SELECT Col1 FROM TABLE2 T2 WHERE T1.Col1 = T2.Col2)
    

    나에게 올바른 결과를 주었다.

    그 이후로 나는 NOT 모든 곳에 존재 사용하기 시작했다.

  8. ==============================

    8.그들은 매우 유사하지만 정말 동일하지 않습니다.

    그들은 매우 유사하지만 정말 동일하지 않습니다.

    효율성의 측면에서, 나는 왼쪽 조인을 발견했습니다 (행의 풍부가 그 선택 될 수있다)보다 효율적으로 널 문이다

  9. ==============================

    9.옵티마이 말한다면 그들은 다음 동일 인간의 요소를 고려한다. I가 존재하지 참조하는 것을 선호합니다 :)

    옵티마이 말한다면 그들은 다음 동일 인간의 요소를 고려한다. I가 존재하지 참조하는 것을 선호합니다 :)

  10. ==============================

    10.하자 우리가 일대 테이블 관계를 형성하는 우리의 데이타베이스는 다음과 같은 두 개의 테이블을 가지고 가정합니다.

    하자 우리가 일대 테이블 관계를 형성하는 우리의 데이타베이스는 다음과 같은 두 개의 테이블을 가지고 가정합니다.

    학생 테이블은 부모, 그리고 학생 테이블의 ID를 기본 키 열을 참조하는 student_id 외래 키 열이 있기 때문에 student_grade 자식 테이블입니다.

    학생 테이블은 다음과 같은 두 개의 레코드를 포함 :

    | id | first_name | last_name | admission_score |
    |----|------------|-----------|-----------------|
    | 1  | Alice      | Smith     | 8.95            |
    | 2  | Bob        | Johnson   | 8.75            |
    

    그리고, student_grade 테이블 저장 성적은 학생들 수신 :

    | id | class_name | grade | student_id |
    |----|------------|-------|------------|
    | 1  | Math       | 10    | 1          |
    | 2  | Math       | 9.5   | 1          |
    | 3  | Math       | 9.75  | 1          |
    | 4  | Science    | 9.5   | 1          |
    | 5  | Science    | 9     | 1          |
    | 6  | Science    | 9.25  | 1          |
    | 7  | Math       | 8.5   | 2          |
    | 8  | Math       | 9.5   | 2          |
    | 9  | Math       | 9     | 2          |
    | 10 | Science    | 10    | 2          |
    | 11 | Science    | 9.4   | 2          |
    

    하자 우리가 수학 클래스 10 등급을받은 모든 학생들을 얻을하고 싶은 말은.

    우리는 단지 학생 식별자에 관심이 있다면, 우리는 이와 같은 쿼리를 실행할 수 있습니다 :

    SELECT
        student_grade.student_id
    FROM
        student_grade
    WHERE
        student_grade.grade = 10 AND
        student_grade.class_name = 'Math'
    ORDER BY
        student_grade.student_id
    

    우리는 학생 테이블에서 정보뿐만 아니라 필요하므로하지만, 응용 프로그램, 학생의 이름 만이 아니라 식별자를 표시에 관심이있다.

    수학에서 10 등급이 학생 레코드를 필터링하기 위해, 우리는이 같은 SQL 연산자를 EXISTS 사용할 수 있습니다 :

    SELECT
        id, first_name, last_name
    FROM
        student
    WHERE EXISTS (
        SELECT 1
        FROM
            student_grade
        WHERE
            student_grade.student_id = student.id AND
            student_grade.grade = 10 AND
            student_grade.class_name = 'Math'
    )
    ORDER BY id
    

    쿼리를 위에 실행하는 경우, 우리는 앨리스 행이 선택되어 있는지를 확인할 수 있습니다 :

    | id | first_name | last_name |
    |----|------------|-----------|
    | 1  | Alice      | Smith     |
    

    외부 쿼리는 우리가 클라이언트에 반환에 관심이있는 학생 행 열을 선택합니다. 그러나, WHERE 절은 연관된 내부 부질와 연산자 존재 사용된다.

    서브 쿼리 반환 적어도 하나의 기록과 거짓 행이 선택되어 있지 않은 경우는 경우는 운영자 true를 반환 존재한다. 데이터베이스 엔진이 완전히 하위 쿼리를 실행할 필요가 없습니다. 하나의 기록이 일치하는 경우, 연산자는 true를 반환 존재하고, 관련된 다른 쿼리 행이 선택됩니다.

    student_grade 테이블의 student_id 열이 외부 학생 테이블의 ID 항목에 대해 일치하기 때문에 내부 부질는 상관된다.

    하자 우리는 낮은 9 이상이 없음 등급이없는 모든 학생을 선택합니다 고려, 우리는하지 EXISTS 연산자의 논리를 부정하는 존재 사용할 수 있습니다.

    기본 하위 쿼리에 대한 기록을 반환하지 않는 경우 따라서 NOT 사실 운영자 반환 존재한다. 하나의 레코드가 부질 내측으로 일치하는 경우에는 상기 NOT 연산자는 false를 반환 존재하고, 서브 쿼리의 실행이 중지 될 수있다.

    어떤 값이 student_grade 9보다 낮은 관련된 모든 학생의 기록과 일치하기 위해, 우리는 다음과 같은 SQL 쿼리를 실행할 수 있습니다 :

    SELECT
        id, first_name, last_name
    FROM
        student
    WHERE NOT EXISTS (
        SELECT 1
        FROM
            student_grade
        WHERE
            student_grade.student_id = student.id AND
            student_grade.grade < 9
    )
    ORDER BY id
    

    쿼리를 위에 실행하는 경우, 우리는 앨리스의 기록이 일치하는 것을 볼 수 있습니다 :

    | id | first_name | last_name |
    |----|------------|-----------|
    | 1  | Alice      | Smith     |
    

    그래서, SQL을 사용하는 이점은 존재하지 내부 하위 쿼리 실행이 오래 일치하는 레코드가 발견으로 중단 될 수 있다는 점이다 운영자 존재한다.

  11. ==============================

    11.때에 따라 다르지..

    때에 따라 다르지..

    SELECT x.col
    FROM big_table x
    WHERE x.key IN( SELECT key FROM really_big_table );
    

    상대적으로들이 키가있는 경우 쿼리 검사 관광지의 제한 크기에 더없는 둔화되지 않을 것이다하는 것은.이 경우에는 바람직 할 것입니다 존재한다.

    단, DBMS의 최적화에 따라,이 다를 수 없었다.

    존재하는 경우의 예는 더 나은로

    SELECT x.col
    FROM big_table x
    WHERE EXISTS( SELECT key FROM really_big_table WHERE key = x.key);
      AND id = very_limiting_criteria
    
  12. from https://stackoverflow.com/questions/173041/not-in-vs-not-exists by cc-by-sa and MIT license