2015-01-26 1 views
2

은 내가 내 데이터베이스에서 실행하고자하는 다음 쿼리는 한 :SQL Server는 다음 쿼리를 어떻게 처리합니까?

SELECT 
    u.UserId, u.FullName, u.Location, csr.SponsorId 
FROM 
    [User] u 
LEFT JOIN 
    (SELECT 
     csr.SponsorId 
    FROM 
     ClubSponsorRelation csr 
    WHERE 
     csr.ClubId = @clubId) AS csr ON u.UserId = csr.SponsorId 
WHERE 
    u.UserType = 'Sponsor' 
    AND csr.SponsorId IS NULL 

이 기본적으로 조인 제외 왼쪽을 실행하려고 아닌 ClubSponsorRelation 테이블의 모든 사용자가 반환됩니다.

제 질문은 에 관한 것입니다. Left Join 이전이나 이후에 SQL Server가이를 고려합니까?

왼쪽 결합 후 WHERE이 적용되는 경우 어떻게 UserType 'Sponsor'를 가진 사용자에 대해서만 왼쪽 결합을 적용 할 수 있는지이 쿼리를 다시 작성할 수 있습니까? 가장 영원한 방법으로도 왼쪽보기가 있습니까? User와 ClubSponsorRelation은 시간이 지남에 따라 상당히 커질 것이고 쿼리는 자주 실행될 것입니다.

+1

SQL을 사용할 인덱스, 통계 및하여 평가 순서를 결정하는 어떤 다른 - 지금까지 당신의 논리가 정확하고 결과는 동일합니다있다. 그러나 "exists()"조건을 사용하면 쿼리를보다 쉽게 ​​읽을 수 있습니다. – Arvo

+0

Luaan이 질문에 대답했지만 왼쪽 가입이 이상한 이유는 무엇입니까? LEFT JOIN ClubSponsorRelation csr on csr.ClubId = @clubId and u.UserId = csr.SponsorId. "and u.UserType = 'Sponsor'"를 추가하여 where 절에서 제거 할 수도 있습니다. –

+0

모든 응답을 주셔서 감사합니다, 나는 그들을 통과하고 내가 허용 될 때마다 적절한 대답을 고를 것입니다. 왜 내 질문에 투표가 내려 졌는지 궁금해. 그것은 합법적 인 질문입니다, 나는 내가하고 싶은 것을 입력 해 주었고, 내가 알고 싶은 것이 분명해 보입니다. –

답변

1

이 기능을 사용해보십시오. ClubSponsorRelation에없는 사용자가 csr.SponsorId을 선택하면 내게 알맞지 않으므로 Not Exists을 사용하여 사용자를 찾으십시오.

SELECT u.UserId, 
     u.FullName, 
     u.Location 
FROM [User] U 
WHERE NOT EXISTS (SELECT 1 
        FROM ClubSponsorRelation csr 
        WHERE u.UserId = csr.SponsorId 
        AND csr.ClubId = @clubId) 
     AND u.UserType = 'Sponsor' 
+0

csr.SponsorID는 IS NULL을 빠뜨린 경우 LEFT JOIN이 NULL을 올바르게 반환했는지 확인하는 것이 었습니다. 내가 LEFT JOIN으로 갔던 이유는 LEFT JOIN이 한 쿼리와 하위 쿼리가 아니기 때문에 LEFT JOIN보다 성능이 뛰어날 것이라고 내 동료가 말했기 때문입니다. 나는 이것이 실제로 사실인지 궁금하다. EXISTS가 나에게 훨씬 더 합리적으로 들리게한다. –

+0

@LennardFonteijn 필자는 '존재하지 않음'을 선호합니다. 대부분의 사례에서 '왼쪽 결합'보다 더 나은 성능을 제공하며 읽기 쉽습니다. 동일한 작업을 수행하는 다양한 기술 간의 성능 비교를 보려면 http://sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join 링크를 확인하십시오. 존재하지 않는 것은 당신의 선택이어야합니다 –

+0

그것은 멋진 링크입니다, 고마워요! –

2

이것은 실행 엔진에 달려 있습니다. 가장 쉬운 방법은 서버에서 실행 계획을 생성하도록하는 것입니다. 예를 들어 Management Studio에서 Include actual execution plan을 확인하십시오. 그러면 쿼리가 실제로 어떻게 실행될 것인지와 그 이유를 알 수 있습니다.

추론은 매우 복잡하며 많은 경우 직관적 인 것처럼 보일 수 있습니다. 예를 들어, 통계에 쿼리가 행의 대부분을 터치 할 것으로 표시되면 인덱스 등을 무시할 수 있습니다. 합리적인 결과를 얻으려면 현실적인 (현실적으로 조정 된) 데이터와 올바르게 유지 관리 된 데이터베이스에서이 작업을 실행해야합니다.

코드 리뷰를 위해 "하위 쿼리"에 가입 할 필요가 없습니다. 대신 다음 두 조건의 조인을 사용하십시오.

left join ClubSponsorRelation csr on csr.ClubId = @clubId and u.UserId = csr.SponsorId 

새 MS SQL 버전이 하위 쿼리를 사용하는 이유는 더 적습니다. 그러나 물론 프로파일 링이 왕입니다. 복잡한 시나리오에서 신뢰할 수있는 추측을하기에는 너무 많은 변수가 있습니다.

이해해야 할 또 다른 중요한 점은 여기서 가능한 성능 문제 만 언급한다는 것입니다.이 문은 평가 순서 등에 의존해서는 안됩니다. 이는 전체 집합/관계 대수 SQL의 일부입니다.

+0

저를 바로 잡아 주셔서 감사합니다. 여러 답변을 받아 들일 수 있으면 좋겠어. 네가 너무 유용했기 때문이다. –

+0

NoDisplayNames의 답변이 확실히 좋습니다. 적어도 MS SQL의 경우 :) 많은 사람들이 서브 쿼리가 자동으로 새로운 커서 또는 뭔가 재미 있다는 것을 의미한다고 생각하는 것 같습니다. 그래도 나는 이와 같은 쿼리를 작성하는 것이 이상하게 느껴진다 : D 그렇지만 시간이 지남에 따라 변할 것이다. EntityFramework의 질의는 실행 플래너를 가능한 한 많이 악용하는 멋진 예입니다 (논란의 여지는 있지만, 복잡한 경우에는 모두 읽을 수있는 것은 아닙니다). – Luaan

0

일반적으로 DBMS는 모든 검색어에 대해 고유 한 검색어 최적화를 수행하며, DBMS는 가장 빠른 것으로 생각하는 알고리즘을 사용합니다. 그래서 필터링 중이고 가입합니다. 하지만 가장 좋은 방법은 Execution Plan입니다.

0

다른 답변은 쿼리 계획에 초점을 맞추 었으므로 나는 그 생각을 나중에 생각하지 않습니다. WHERE 절은 FROM 절이 작성한 모든 행 또는 단어의 JOIN 뒤에 적용되는 모든 행에 적용됩니다. JOIN에서 필터를 적용하려면 다른 조건으로 필터를 추가하면됩니다.

SELECT 
    u.UserId, 
    u.FullName, 
    u.Location, 
    csr.SponsorId 
FROM 
    [User] u 
     LEFT JOIN ClubSponsorRelation csr ON csr.SponsorId = u.UserId 
             and csr.ClubId = @clubId 
             and u.UserType = 'Sponsor' 
WHERE 
    csr.SponsorId IS NULL 
+0

물론 여전히 동일합니다. 쿼리 최적화 프로그램에 대한 힌트를 제공합니다. 아마도. 요점은 대수학이 모호하지 않으며, 예를 들어 대수학에 의존하지 않는다는 것입니다. 조작의 순서 실제 실행 계획이 다르게 끝나는 경우 이는 기본 쿼리 (이 경우 동일한 경우)가 아닌 최적화 프로그램의 제한 사항 (실행 계획에 잘 표시됨) 때문입니다. – Luaan

+0

@Luaan - LEFT JOIN이기 때문에 같은 작업이 아닙니다. 예를 들어 원래 쿼리는 스폰서 사용자 유형 만 반환하고 내 쿼리는 모든 사용자 유형을 반환합니다. 이것이 올바른지 아닌지는 원래의 포스터가 원하는 것에 달려 있습니다. –

+0

네 말이 맞아, 나는 그 점을 놓쳤다. 나는 당신이 'UserType' 조건을 거기로 옮겼다는 사실을 정말로 느끼지 못했습니다. 내 의견은 서브 쿼리에 대한 조인이 아니라 첫 번째 두 조건을 단일 조인으로 이동하는 것에 관한 것입니다. 'UserType'을 움직이면 원래 있던 것과 다른 세트에 적용됩니다. – Luaan

0

쿼리 실행 방법은 DBMS의 책임입니다. 그리고 명령이 결과에 영향을 미치지 않으므로 너무 걱정하지 않아야합니다. 일반적으로 옵티마이 저는 가장 효율적인 방법을 찾습니다. 이것은 한 방향 일 수도 있고 다른 방향 일 수도 있습니다. 좋은 일을하고 성능 문제가 발생할 경우에만 대안을 찾기 시작하는 것이 좋을 것입니다.

귀하의 검색어는 이미 방어 적 사고를 보여줍니다. 특정 클럽의 스폰서가 아닌 사용자를 확보하려고합니다. 그렇다면 NOT IN 또는 NOT EXISTS를 사용하는 이유는 무엇입니까? 이것은 똑 바른 방법 일 것입니다 (또한 읽기 쉬울 것입니다). 옵티마이 저는 내부적으로 외부 조인을 사용하기로 결정할 수 있지만 일반적인 쿼리로 문제가 발생하기 전에 왜 그런 트릭을 생각해야할까요?

이렇게 말한 결과, 잘 작동하는 한 NOT IN 또는 NOT EXIST를 사용하는 것이 좋습니다.

select userid, fullname, location 
from [User] 
where usertype = 'Sponsor' 
and userid not in 
(
    select sponsorid 
    from clubsponsorrelation 
    where clubid = @clubid 
); 

또는 :

select userid, fullname, location 
from [User] u 
where usertype = 'Sponsor' 
and not exists 
(
    select * 
    from clubsponsorrelation csr 
    where csr.clubid = @clubid 
    and csr.sponsorid = u.userid 
); 
+0

'subquery'가'NULL'을 반환 할 때'Not in'은 실패 할 것입니다. –

+0

@NoDisplayName : 그러나 ClubSponsorRelation의 이상한 항목은 클럽과 스폰서 간의 관계를 보여주는 유일한 목적일까요? –

+0

전적으로 동의하지만 여전히 'Null'값이있을 수 있습니다. 그것의 다만 제안. –

관련 문제