SQL 조인 대 SQL 하위 쿼리 (성능)?


110

다음과 같은 조인 쿼리 가 있는지 알고 싶습니다.

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

다음과 같은 하위 쿼리 -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

성능 을 고려할 때 두 쿼리 중 어느 것이 더 빠르며 그 이유는 무엇입니까?

또한 내가 다른 것보다 하나를 선호해야 할 때가 있습니까?

이것이 너무 사소하고 전에 물어 보면 미안하지만 혼란 스럽습니다. 또한 두 쿼리의 성능을 측정하는 데 사용해야하는 도구를 제안 해 주시면 좋을 것 입니다. 감사합니다!


5
@Lucero,이 질문은 sql-server-2008 태그가 있으며, 여기서 언급 한 게시물은 MySql 태그입니다. 답이 같을 것이라고 추론 할 수 있습니다. 성능 최적화는 두 RDBMS에서 다르게 수행됩니다.
Francois Botha 2012

답변:


48

주로 동등성과 명시 적 JOIN이 있기 때문에 첫 번째 쿼리가 더 빠를 것으로 예상합니다. 내 경험상 IN매우 느린 연산자입니다. SQL은 일반적으로 WHERE"OR"( WHERE x=Y OR x=Z OR...)로 구분 된 일련의 절로 평가하기 때문 입니다.

그러나 ALL THINGS SQL과 마찬가지로 마일리지는 다를 수 있습니다. 속도는 무엇보다도 인덱스에 따라 크게 달라집니다 (두 ID 열에 인덱스가 있습니까? 많은 도움이 될 것입니다 ...).

더 빠른 것을 100 % 확실하게 알 수있는 유일한 방법은 성능 추적을 켜고 (IO 통계가 특히 유용함) 둘 다 실행하는 것입니다. 실행 사이에 캐시를 지우십시오!


16
대부분의 DBMS (확실히 SQL Server 2008 이상)는 단일 ID 하위 쿼리 (상관되지 않음, 즉 여러 외부 쿼리 열을 참조하지 않음)를 비교적 빠른 세미 조인으로 변환하기 때문에이 대답에 대해 심각한 의문이 있습니다. 또한 이전에 다른 답변에서 언급했듯이 첫 번째 실제 조인은 Dept에서 일치하는 ID의 각 발생에 대해 행을 반환합니다. 이것은 고유 ID에 대해서는 차이가 없지만 다른 곳에서 많은 중복을 제공합니다. DISTINCT 또는 GROUP BY를 사용하여 이러한 항목을 정렬하면 또 다른 높은 성능 부하가 발생합니다. SQL Server Management Studio에서 실행 계획을 확인하십시오!
에릭 하트

2
OR에 해당하는 IN 절은 매개 변수 / 값 목록에 적용되지만 대부분 조인처럼 취급되는 하위 쿼리에는 적용되지 않습니다.
에릭 하트

42

글쎄, 나는 그것이 "오래되었지만 금"질문이라고 믿는다. 대답은 "상황에 따라 다릅니다!"입니다. 공연은 너무 섬세해서 "서브 쿼리를 사용하지 말고 항상 참여하라"고 말하기에는 너무 어리석은 주제입니다. 다음 링크에서 내가 매우 유용하다고 판단한 몇 가지 기본 모범 사례를 찾을 수 있습니다.

50000 개의 요소가있는 테이블이 있는데, 내가 찾고 있던 결과는 739 개의 요소였습니다.

처음에 내 질문은 다음과 같습니다.

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

실행하는 데 7.9 초가 걸렸습니다.

마침내 내 질문은 다음과 같습니다.

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

0.0256 초가 걸렸습니다.

좋은 SQL, 좋아요.


3
흥미롭게도 GROUP BY를 추가하면 어떻게 수정되었는지 설명해 주시겠습니까?
cozos

6
하위 쿼리에 의해 생성 된 임시 테이블이 더 작습니다. 따라서 체크인 할 데이터가 적기 때문에 실행이 더 빠릅니다.
Sirmyself

2
첫 번째 쿼리에서는 외부 쿼리와 하위 쿼리간에 변수를 공유한다고 생각하므로 기본 쿼리의 모든 행에 대해 하위 쿼리가 실행되지만 두 번째 쿼리에서는 하위 쿼리가 한 번만 실행되므로 성능이 향상됩니다.
Ali Faradjpour 2019

1
SQL 서버와 MySql 및 ... Sql (NoSql 제외)은 인프라에서 매우 유사합니다. IN (...) 절을 조인 (가능하다면)으로 변환하는 일종의 쿼리 최적화 엔진이 그 아래에 있습니다. 그러나 잘 인덱싱 된 열 (카디널리티 기준)에 Group by가 있으면 훨씬 빠릅니다. 그래서 상황에 따라 다릅니다.
Alix

10

실행 계획을 살펴보고 SQl 서버가이를 해석하는 방법의 차이점을 확인하십시오. Profiler를 사용하여 실제로 쿼리를 여러 번 실행하고 차이점을 얻을 수 있습니다.

상호 관련된 하위 쿼리를 사용할 때 하위 쿼리 대신 조인을 사용하여 실제 큰 성능 향상을 얻을 수있는 경우 이러한 항목이 그렇게 끔찍하게 다를 것이라고 기대하지 않습니다.

EXISTS는 종종이 두 가지 중 하나보다 낫고 왼쪽 조인 테이블에없는 모든 레코드를 원하는 왼쪽 조인을 말할 때 NOT EXISTS가 종종 훨씬 더 나은 선택입니다.


9

성능은 실행중인 데이터의 양을 기반으로합니다.

20k 정도의 데이터가 적다면. JOIN이 더 잘 작동합니다.

데이터가 100k +와 비슷하면 IN이 더 잘 작동합니다.

다른 테이블의 데이터가 필요하지 않으면 IN이 좋지만 EXISTS로 이동하는 것이 좋습니다.

이 모든 기준을 테스트했으며 테이블에는 적절한 색인이 있습니다.


4

성능은 동일해야합니다. 테이블에 올바른 인덱스와 클러스터링을 적용하는 것이 훨씬 더 중요합니다 ( 해당 주제에 대한 좋은 리소스 가 있습니다 ).

(업데이트 된 질문을 반영하도록 수정 됨)


4

두 쿼리는 의미 상 동일하지 않을 수 있습니다. 직원이 둘 이상의 부서에서 일하는 경우 (제가 일하는 기업에서 가능합니다. 물론 이것은 테이블이 완전히 정규화되지 않았 음을 의미합니다) 첫 번째 쿼리는 중복 행을 반환하지만 두 번째 쿼리는 그렇지 않습니다. 이 경우 쿼리를 동등하게 만들려면 DISTINCT키워드를 SELECT절에 추가해야하므로 성능에 영향을 미칠 수 있습니다.

테이블이 엔터티 / 클래스 또는 엔터티 / 클래스 간의 관계를 모델링해야하지만 둘다는 아니어야한다는 설계 규칙이 있습니다. 따라서 OrgChart직원과 부서 간의 관계를 모델링하기 위해 세 번째 테이블 (예 :)을 만드는 것이 좋습니다 .


4

나는 이것이 오래된 게시물이라는 것을 알고 있지만 이것은 매우 중요한 주제라고 생각합니다. 특히 오늘날 우리는 1 천만 이상의 레코드를 가지고 있고 테라 바이트의 데이터에 대해 이야기하고 있습니다.

나는 또한 다음과 같은 관찰에 무게를 둘 것이다. 내 테이블 ([data])에는 약 4,500 만 개의 레코드가 있고 [cats] 테이블에는 약 300 개의 레코드가 있습니다. 내가 이야기하려는 모든 쿼리에 대해 광범위한 인덱싱이 있습니다.

예 1을 고려하십시오.

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

대 예 2 :

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

예제 1은 실행하는 데 약 23 분이 걸렸습니다. 예제 2는 약 5 분이 걸렸습니다.

따라서이 경우 하위 쿼리가 훨씬 빠르다는 결론을 내릴 수 있습니다. 물론 1GB / sec에서 i / o가 가능한 M.2 SSD 드라이브 (비트가 아닌 바이트)를 사용하고 있으므로 인덱스도 정말 빠릅니다. 따라서 이것은 당신의 상황에서도 속도에 영향을 미칠 수 있습니다

일회성 데이터 정리 인 경우 실행하고 종료하는 것이 가장 좋습니다. 나는 TOP (10000)을 사용하고 얼마나 오래 걸리는지 확인하고 큰 쿼리에 도달하기 전에 레코드 수를 곱합니다.

프로덕션 데이터베이스를 최적화하는 경우 실시간 액세스가 정적 데이터를 검색하도록 트리거 또는 작업 브로커를 사용하여 레코드를 비 동기화하는 등 데이터 전처리를 강력히 제안합니다.


0

계획 설명을 사용하여 객관적인 답변을 얻을 수 있습니다.

문제의 경우 Exists 필터 가 가장 빨리 수행 될 것입니다.


2
"존재 필터는 아마도 가장 빠른 성능을 발휘할 것"입니다. 확실한 답을 얻으려면 실제 데이터에 대한 테스트가 필요하지만 아마도 그렇지 않을 것입니다. 기존 필터는 동일한 조회 값을 가진 여러 행이있는 경우 더 빠를 수 있습니다. 따라서 쿼리가 다른 직원이 동일한 부서에서 기록되었는지 여부를 확인하는 경우 존재 필터가 더 빠르게 실행될 수 있지만 부서를 조회 할 때는 그렇지 않을 수 있습니다. 표.

마지막 시나리오에서 더 느리게 실행 될까요?
Snekse 2010 년

옵티 마이저에 따라 달라집니다. 특정 상황에서는 그럴 수도 있지만 일반적으로 매우 유사한 성능을 기대합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.