문제

기본 키가 다른 테이블에있는 테이블에서 행을 선택하고 싶습니다. SQL Server 2005의 조인지 또는 IN 연산자를 사용해야하는지 확실하지 않습니다. 큰 데이터 세트 (예 : 수백만 행)가있는이 두 SQL 쿼리 사이에 상당한 성능 차이가 있습니까?

SELECT *
FROM a
WHERE a.c IN (SELECT d FROM b)

SELECT a.*
FROM a JOIN b ON a.c = b.d
도움이 되었습니까?

해결책

업데이트:

내 블로그 의이 기사는 내 답변과 다른 답변에 대한 내 의견을 모두 요약하고 실제 실행 계획을 보여줍니다.


SELECT  *
FROM    a
WHERE   a.c IN (SELECT d FROM b)

SELECT  a.*
FROM    a
JOIN    b
ON      a.c = b.d

이 쿼리는 동일하지 않습니다. 테이블이라면 다른 결과를 얻을 수 있습니다 b 키가 유지되지 않습니다 (즉, 값은 b.d 독특하지 않습니다).

첫 번째 쿼리와 동일합니다.

SELECT  a.*
FROM    a
JOIN    (
        SELECT  DISTINCT d
        FROM    b
        ) bo
ON      a.c = bo.d

만약에 b.d ~이다 UNIQUE 그리고 (a UNIQUE INDEX 또는 UNIQUE CONSTRAINT), 그러면 이러한 쿼리는 동일하며 아마도 동일한 계획을 사용할 것입니다. SQL Server 이것을 고려할만큼 똑똑합니다.

SQL Server 이 쿼리를 실행하기 위해 다음 방법 중 하나를 사용할 수 있습니다.

  • 인덱스가있는 경우 a.c, d ~이다 UNIQUE 그리고 b 에 비해 상대적으로 작습니다 a, 그런 다음 조건은 하위 쿼리와 평원으로 전파됩니다. INNER JOIN 사용됩니다 ( b 주요한)

  • 인덱스가있는 경우 b.d 그리고 d 아니다 UNIQUE, 그런 다음 조건도 전파되고 LEFT SEMI JOIN 사용. 위의 상태에도 사용할 수 있습니다.

  • 둘 다에 인덱스가있는 경우 b.d 그리고 a.c 그리고 그들은 크다 MERGE SEMI JOIN 사용

  • 테이블에 색인이 없으면 해시 테이블이 구축됩니다. b 그리고 HASH SEMI JOIN 사용.

어느 것도 아니다 이 방법 중 하나는 매번 전체 하위 쿼리를 재평가합니다.

이것이 어떻게 작동하는지에 대한 자세한 내용은 내 블로그 에서이 항목을 참조하십시오.

모두를위한 링크가 있습니다 RDBMSBig Four의 S.

다른 팁

어느 것도 아니다. ANSI-92 조인을 사용하십시오.

SELECT a.*
FROM a JOIN b a.c = b.d

그러나 존재하는대로 최고입니다

SELECT a.*
FROM a
WHERE EXISTS (SELECT * FROM b WHERE a.c = b.d)

이것은 조인으로 생성 될 수있는 복제물을 제거하지만 더 빠르지 않으면 빠르게 실행됩니다.

IN은 A의 각 행에 대해 평가 (및 B 재현 중에서 선택)이며, 결합은 인덱스 및 기타 깔끔한 페이징 트릭을 사용하도록 최적화됩니다 ...

그러나 대부분의 경우 Optimizer는 상관 관계 서브 쿼리에서 조인을 구성하고 어쨌든 동일한 실행 계획으로 끝날 수 있습니다.

편집 :이 답변의 유효성과 OP의 질문에 대한 실제 답변에 대한 토론을 위해 아래의 의견을 친절하게 읽으십시오. =))

49,000,000 행의 테이블에서 경험을 통해 왼쪽 외부 조인을 권장합니다. IN을 사용하거나 존재하는 경우 왼쪽 외부 결합이 1 초 안에 마무리되는 위치를 완료하는 데 5 분이 걸렸습니다.

SELECT a.*
FROM a LEFT OUTER JOIN b ON a.c = b.d
WHERE b.d is not null -- Given b.d is a primary Key with index

실제로 내 쿼리에서 나는 9 개의 테이블에서 이것을한다.

자신을 위해 큰 테스트 데이터를 사용하여 실제로 테스트하는 것 외에도 결합을 사용한다고 말할 것입니다. 나는 대부분의 경우 하위 쿼리에 비해 대부분의 경우에 이들을 사용하여 더 나은 성능을 가지고 있었고, 결합하는 방법, 선택한 내용, 그렇지 않은 것 등 더 많은 사용자 정의 옵션이 있습니다.

결과는 다른 쿼리입니다. 쿼리를 사용하면 술어가 일치 할 때마다 테이블 'A'에서 1 줄이 나타납니다. 내부 조인 쿼리를 사용하면 조인 조건이 일치 할 때마다 A*B 행이 나타납니다. 따라서 {1,2,3}의 A의 값과 {1,2,2,3}의 B의 값을 사용하면 조인에서 1,2,2,3, IN에서 1,2,3을 얻게됩니다.

편집 - 나는 당신이 여기에서 당신에게 오해를 줄 수있는 몇 가지 답변을 발견 할 수 있다고 생각합니다. 직접 테스트하면 이들이 모두 훌륭한 쿼리 계획임을 알 수 있습니다.

create table t1 (t1id int primary key clustered)
create table t2 (t2id int identity primary key clustered
    ,t1id int references t1(t1id)
)


insert t1 values (1)
insert t1 values (2)
insert t1 values (3)
insert t1 values (4)
insert t1 values (5)

insert t2 values (1)
insert t2 values (2)
insert t2 values (2)
insert t2 values (3)
insert t2 values (4)


select * from t1 where t1id in (select t1id from t2)
select * from t1 where exists (select 1 from t2 where t2.t1id = t1.t1id)
select t1.* from t1 join t2 on t1.t1id = t2.t1id

처음 두 계획은 동일합니다. 마지막 계획은 중첩 루프이며, 위에서 언급 한 바와 같이 Join은 다른 의미를 갖기 때문에이 차이가 예상됩니다.

에서 MSDN 문서 하위 정체 기초 :

하위 쿼리를 포함하는 많은 Transact-SQL 문은 대안 적으로 결합으로 공식화 될 수 있습니다. 다른 질문은 하위 쿼리로만 제기 될 수 있습니다. Transact-SQL에서는 일반적으로 서브 쿼리와 의미 적으로 동등한 버전을 포함하는 문 사이에 성능 차이가 없습니다. 그러나 존재를 점검 해야하는 경우에도 결합은 더 나은 성능을 얻습니다. 그렇지 않으면 중첩 쿼리를 외부 쿼리의 각 결과마다 처리하여 복제물을 제거해야합니다. 이러한 경우 조인 접근 방식은 더 나은 결과를 산출 할 것입니다.

제공 한 예제에서 중첩 쿼리는 각 외부 쿼리 결과에 대해 한 번만 처리되므로 성능 차이가 없어야합니다. 두 쿼리에 대한 실행 계획을 확인하면이를 확인해야합니다.

참고 : 질문 자체는 SQL Server 2005를 지정하지 않았지만 질문 태그를 기반으로 해당 가정으로 대답했습니다. 다른 데이터베이스 엔진 (다른 SQL 서버 버전도)도 같은 방식으로 최적화되지 않을 수 있습니다.

두 유형 모두에 대한 실행 계획을 관찰하고 결론을 도출하십시오. "in"명령문에서 하위 퀘스트가 반환 한 레코드의 수가 매우 작지 않는 한, IN 변형은 거의 느슨합니다.

나는 가입을 사용하여 그것이 내에서 훨씬 더 빨리 가질 것이라고 내기합니다. 이것은 물론 기본 키가 정의되어 있다고 가정하므로 인덱싱 속도가 엄청나게 높아집니다.

일반적으로 조인은 IN 하위 쿼리보다 더 효율적일 것이라고 주장된다. 그러나 SQL*서버 최적화는 일반적으로 눈에 띄는 성능 차이가 없습니다. 그럼에도 불구하고 조인 조건을 사용하여 표준을 일관성있게 유지하는 것이 가장 좋습니다. 또한 미래에 데이터와 코드를 마이그레이션 해야하는 경우 데이터베이스 엔진은 그렇게 용서하지 않을 수 있습니다 (예 : In In Subquery 대신 조인을 사용하면 MySQL에 큰 차이가 있습니다).

이론은 이와 같은 질문에 대해서만 당신을 데려 갈 것입니다. 하루가 끝나면 두 쿼리를 모두 테스트하고 실제로 더 빠르게 실행되는지 확인하고 싶을 것입니다. 조인 버전이 1 분이 걸렸고 IN 버전이 1 초도 걸리는 경우가있었습니다. 나는 또한 가입이 실제로 더 빠른 경우도있었습니다.

개인적으로, 나는 하위 쿼리 테이블의 필드가 필요하지 않다는 것을 알고 있다면 IN 버전으로 시작하는 경향이 있습니다. 느리게 실행되기 시작하면 최적화하겠습니다. 다행스럽게도 대규모 데이터 세트의 경우 쿼리를 다시 작성하면 쿼리 분석기에서 시간을 보내고 진행 중이라는 것을 알 수 있습니다.

행운을 빕니다!

Ive는 항상 IN 방법론의 지지자였습니다. 이 링크에는 postgressql에서 수행 된 테스트의 세부 사항이 포함되어 있습니다.http://archives.postgresql.org/pgsql-performance/2005-02/msg00327.php

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top