programing

SQL Server에서의 내부 참여와 왼쪽 참여의 퍼포먼스

instargram 2023. 4. 7. 20:53
반응형

SQL Server에서의 내부 참여와 왼쪽 참여의 퍼포먼스

9개의 테이블에서 INSER JOIN을 사용하는 SQL 명령어를 작성했습니다.어쨌든 이 명령어는 매우 오랜 시간(5분 이상) 걸립니다).그래서 제가 알기로는 LEFT JOIN의 퍼포먼스가 더 좋으니까 LEFT JOIN을 LEFT JOIN으로 바꾸라고 했어요.변경 후 쿼리 속도가 대폭 향상되었습니다.

LEFT JOIN이 INSER JOIN보다 빠른 이유가 궁금합니다.

SQL の sql음음 sql sql sql 。SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN D

업데이트: 스키마의 개요입니다.

FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
    INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
        ON a.CompanyCd = b.CompanyCd 
           AND a.SPRNo = b.SPRNo 
           AND a.SuffixNo = b.SuffixNo 
           AND a.dnno = b.dnno
    INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
        ON a.CompanyCd = h.CompanyCd
           AND a.sprno = h.AcctSPRNo
    INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
        ON c.CompanyCd = h.CompanyCd
           AND c.FSlipNo = h.FSlipNo 
           AND c.FSlipSuffix = h.FSlipSuffix 
    INNER JOIN coMappingExpParty d -- NO PK AND FK
        ON c.CompanyCd = d.CompanyCd
           AND c.CountryCd = d.CountryCd 
    INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
        ON b.CompanyCd = e.CompanyCd
           AND b.ProductSalesCd = e.ProductSalesCd 
    LEFT JOIN coUOM i -- PK = UOMId
        ON h.UOMId = i.UOMId 
    INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
        ON a.CompanyCd = j.CompanyCd
            AND b.BFStatus = j.BFStatus
            AND b.ProductSalesCd = j.ProductSalesCd
    INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
        ON e.ProductGroup1Cd  = g1.ProductGroup1Cd
    INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
        ON e.ProductGroup1Cd  = g2.ProductGroup1Cd

A LEFT JOIN INNER JOIN. 실제로는 속도가 느립니다.외부 참여LEFT JOIN ★★★★★★★★★★★★★★★★★」RIGHT JOIN은(는).INNER JOIN또한 결과를 무효로 하는 추가 작업도 있습니다.또한 더 많은 행을 반환할 것으로 예상되며, 단순히 결과 집합의 크기가 크기 때문에 총 실행 시간이 더 길어집니다.

(또)이 있어도LEFT JOIN 특정 상황에서 특정 요인의 결합으로 인해 속도가 더 빨랐지만 기능적으로는 동일하지 않습니다.INNER JOIN따라서 단순히 하나의 인스턴스를 다른 인스턴스로 교체할 수는 없습니다.)

대부분의 경우 퍼포먼스 문제는 후보 키나 외부 키를 적절히 색인화하지 않는 등 다른 곳에 있을 수 있습니다.9개의 테이블은 결합하는 것이 꽤 많기 때문에 속도 저하는 말 그대로 어디에나 있을 수 있습니다.스키마를 투고해 주시면 자세한 내용을 알려드릴 수 있을 것 같습니다.


편집:

한 번 해 보면, 는 한 가지 해 볼 수 .LEFT JOIN 더 도 모른다INNER JOIN 되면 '어,어,어,어,어,어,어,어,어,어,어,어,어,어,어,어,어,어,어.

  • 일부 테이블은 매우 작습니다(예를 들어 10열 미만).
  • 테이블에 충분한 인덱스가 없어 쿼리를 처리할 수 없습니다.

다음 예를 생각해 보겠습니다.

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

「 」가 표시됩니다.INNER JOIN는 실제로 .LEFT JOIN위의 두 가지 기준을 충족하기 때문입니다.가 "SQL Server" 해시 매치에 대해 INNER JOIN ", "의 LEFT JOIN보통 전자가 훨씬 빠르지만 행의 수가 너무 적고 사용할 인덱스가 없기 때문에 해시 연산이 쿼리에서 가장 비용이 많이 드는 것으로 나타났습니다.

원하는 프로그래밍 언어로 프로그램을 작성하여 5개의 요소가 있는 해시 테이블과 비교하여 5개의 요소가 있는 목록에서 많은 조회를 수행함으로써 동일한 효과를 볼 수 있습니다.크기 때문에 해시 테이블버전은 실제로는 느립니다.그러나 50개의 요소 또는 5000개의 요소로 늘리면 해시 테이블의 O(N) 대 O(1)이므로 목록 버전이 크롤로 느려집니다.

, 이 를 "" " " " " "로합니다.ID이 아닌Name아주 다른 이야기를 보게 될 겁니다.쿼리에 되지만, " "는 " " " 입니다.INNER JOIN버전은 클러스터된 인덱스 스캔 중 하나를 검색으로 대체할 수 있습니다. 즉, 말 그대로 행 수가 많을수록 훨씬 더 빠릅니다.

결론은 위에서 언급한 몇 가지 단락입니다.이것은 인덱스 또는 인덱스 커버리지의 문제이며, 1개 이상의 매우 작은 테이블과 조합되어 있을 가능성이 있습니다.SQL Server가 더 나쁜 실행 계획을 선택할 수 있는 유일한 상황입니다.INNER JOIN 훨씬LEFT JOIN.

아직 논의되지 않은 내부 조인보다 외부 조인 속도가 더 빨라질 수 있는 중요한 시나리오가 하나 있습니다.

외부 조인을 사용하는 경우 조인 열이 외부 테이블의 PK이고 외부 테이블 열이 외부 조인 자체 외부에서 참조되지 않으면 옵티마이저는 항상 실행 계획에서 외부 조인 테이블을 자유롭게 삭제할 수 있습니다.를 들어, 「」입니다.SELECT A.* FROM A LEFT OUTER JOIN B ON A.KEY=B.KEY입니다.KEY 입 B 니 PK 니 key 。Oracle(릴리스 10을 사용하고 있었던 것 같음)과 SQL Server(2008 R2) 모두 실행 계획에서 테이블 B를 삭제합니다.

조인에도 . 즉, 이너 조인에는 해당되지 않습니다.SELECT A.* FROM A INNER JOIN B ON A.KEY=B.KEY어떤 제약조건이 존재하느냐에 따라 실행계획에서 B를 요구할 수도 있고 그렇지 않을 수도 있습니다.

A.KEY가 B를 참조하는 늘 가능한 외부 키인 경우.KEY 그러면 최적기는 A 행마다 B 행이 존재하는지 확인해야 하므로 B를 계획에서 삭제할 수 없습니다.

A.KEY가 B를 참조하는 필수 외부 키인 경우.KEY, 그러면 제약조건이 행의 존재를 보증하기 때문에 최적기는 B를 계획에서 자유롭게 삭제할 수 있습니다.하지만 옵티마이저가 계획에서 테이블을 삭제할 수 있다고 해서 그렇게 되는 것은 아닙니다.SQL Server 2008 R2는 B를 계획에서 삭제하지 않습니다.Oracle 10은 B를 계획에서 제외합니다.이 경우 외부 조인이 SQL Server에서 내부 조인을 어떻게 능가하는지 쉽게 알 수 있습니다.

이는 단순한 예이며 독립형 쿼리에 실용적이지 않습니다.필요 없는데 왜 테이블에 앉는 거죠?

그러나 이는 뷰를 설계할 때 매우 중요한 설계 고려사항이 될 수 있습니다.중앙 테이블과 관련하여 사용자에게 필요한 모든 것을 결합하는 "do-everything" 뷰가 구축되는 경우가 많습니다(특히 관계 모델을 이해하지 못하는 애드혹 쿼리를 실행하는 순진한 사용자가 있는 경우).뷰에는 많은 테이블의 모든 관련 열이 포함될 수 있습니다.그러나 최종 사용자는 보기 내 테이블의 하위 집합에서만 열에 액세스할 수 있습니다.테이블이 외부 조인과 결합되어 있는 경우 옵티마이저는 불필요한 테이블을 계획에서 폐기할 수 있습니다.

외부 조인을 사용하는 뷰가 올바른 결과를 제공하는지 확인하는 것이 중요합니다.Aaronaught가 말했듯이, 무작정 OUTER JOIN을 INSER JOIN으로 대체하여 동일한 결과를 기대할 수 없습니다.그러나 뷰를 사용할 때 성능상의 이유로 유용할 수 있습니다.

마지막 주의 - 위의 점에 비추어 퍼포먼스에 미치는 영향은 테스트하지 않았습니다만, 이론적으로는 where 절에 <FOREAND_KEY>가 NULL이 아닌 조건도 추가한다면, 이너 조인(INHER JOIN)을 OUTER JOIN)으로 안전하게 교환할 수 있을 것 같습니다.

모든 것이 정상 작동해서는 안 되지만, 특히 쿼리 최적화 도구, 쿼리 계획 캐싱 및 통계에 관한 모든 것이 정상 작동되지 않는다는 것을 모두 알고 있습니다.

먼저 인덱스와 통계를 재구축하고 쿼리 계획 캐시를 클리어하는 것이 좋습니다.이것이 일을 망치지 않도록 하기 위해서입니다.하지만 저는 그 후에도 문제를 겪었습니다.

이너 조인보다 왼쪽 조인이 더 빠른 경우도 있습니다.

근본적인 이유는 다음과 같습니다.테이블이 두 개이고 인덱스가 있는 열(양쪽 테이블)에 결합하는 경우.테이블 1의 인덱스에 있는 엔트리를 루프하여 테이블2의 인덱스와 대조해도 내부 조인에서는 다음과 같이 같은 결과가 나타납니다.테이블 2의 인덱스에 있는 엔트리를 루프오버하고 테이블1의 인덱스와 일치시킵니다.문제는 잘못된 통계가 있는 경우 쿼리 최적화 도구에서 인덱스의 통계를 사용하여 (다른 기준에 따라) 가장 일치하는 엔트리가 적은 테이블을 찾는다는 것입니다.각각 100만 개의 테이블이 2개 있는 경우 테이블1에는 10개의 행이 일치하고 테이블2에는 100000개의 행이 일치합니다.가장 좋은 방법은 테이블 1에서 인덱스 스캔을 수행하고 테이블 2에서 10회 일치시키는 것입니다.반대로 100000행 이상의 행을 루프하여 100000회 매칭을 시도하여 10회만 성공하는 인덱스스캔이 됩니다따라서 통계가 정확하지 않으면 옵티마이저는 루프오버할 테이블과 인덱스를 잘못 선택할 수 있습니다.

최적기가 왼쪽 조인을 기록된 순서대로 최적화하도록 선택하면 내부 조인보다 성능이 향상됩니다.

단, 옵티마이저는 왼쪽 세미 조인으로 최적화할 수도 있습니다.원하는 항목을 선택하려면 강제 순서 힌트를 사용하면 됩니다.

조인이 쿼리)를 시험해 .OPTION (FORCE ORDER)결과를 게시할 수 있습니다. OPTION (FORCE ORDER)는 쿼리에서 지정한 조인 순서를 사용하여 옵티마이저가 실행 계획을 강제로 구축하도록 하는 쿼리 힌트입니다.

ifINNER JOIN같은 속도로 동작하기 시작합니다.LEFT JOIN는 다음과 같습니다

  • ""로 "INNER JOIN.이를 통해 쿼리 옵티마이저는 적합하다고 판단되는 조인을 자유롭게 정렬할 수 있으므로 문제는 옵티마이저에 의존할 수 있습니다.
  • ★★★★★★★★★★★★★★★★ LEFT JOIN가입 순서를 변경하면 쿼리 결과가 변경되기 때문에 그렇지 않습니다.조인 순서보다 수 .이것은 최적화된 조인 순서보다 나을 수 있습니다.

이것이 당신의 질문에 대답할 수 있을지는 모르겠지만, 나는 한때 매우 복잡한 쿼리를 통해 계산을 하는 프로젝트에 참여했는데, 이것이 최적화 도구를 완전히 엉망으로 만들었다.FORCE ORDER쿼리 실행 시간이 5분에서 10초로 단축됩니다.

좌측 외측 조인과 내측 조인을 여러 번 비교했지만 일관된 차이를 찾을 수 없었습니다.변수가 많습니다.수천 개의 테이블이 있는 보고서 데이터베이스에서 작업하고 있습니다.이 데이터베이스에는 다수의 필드가 있으며 시간이 지남에 따라 많은 변경이 이루어지고 있습니다(벤더 버전 및 로컬 워크플로우).이러한 다양한 쿼리의 요구를 충족하고 이력 데이터를 처리하기 위해 커버링 인덱스의 모든 조합을 생성할 수는 없습니다.내부 쿼리는 2개의 큰 테이블(수백만에서 수천만 행)이 내부 결합되어 다수의 필드를 끌어당기고 커버링 인덱스가 존재하지 않기 때문에 서버의 퍼포먼스를 저하시키는 것을 확인했습니다.

그러나 가장 큰 문제는 위의 논의에서 진정되지 않는 것 같다.데이터베이스에는 트리거와 트랜잭션 처리를 적절히 설계하여 양호한 데이터를 보장할 수 있습니다.내 값은 예기치 않은 NULL 값을 갖는 경우가 많습니다.예, 테이블 정의에서는 no-nulls를 적용할 수 있지만 내 환경에서는 이 옵션을 사용할 수 없습니다.

그래서 질문은...1분에 수천 번 동일한 코드를 실행하는 트랜잭션 처리의 높은 우선 순위인 속도만을 위해 쿼리를 설계합니다.아니면 왼쪽 외부 결합이 제공하는 정확성을 추구합니까?이너 조인은 양쪽에서 일치하는 것을 찾을 필요가 있기 때문에 예기치 않은 NULL은 2개의 테이블에서 데이터를 삭제할 뿐만 아니라 정보의 행 전체를 삭제할 수도 있습니다.오류 메시지 없이 아주 잘 진행됩니다.

필요한 데이터의 90%를 취득하고 내부 조인에서 자동으로 삭제된 정보를 검출하지 않기 때문에 매우 신속하게 처리할 수 있습니다.때로는 내부 가입이 더 빠를 수도 있지만, 실행 계획을 검토하지 않는 한 그런 가정을 하는 사람은 없을 것입니다.속도도 중요하지만 정확성이 더 중요하다.

외부 조인은 뷰에서 사용할 때 뛰어난 성능을 제공할 수 있습니다.

뷰와 관련된 쿼리가 있고 해당 뷰가 결합된 10개의 테이블로 구성되어 있다고 가정합니다.쿼리에서 10개의 테이블 중 3개의 열만 사용한다고 가정해 보십시오.

이들 10개의 테이블이 내부 결합되어 있는 경우 쿼리 자체는 10개의 테이블 중 7개가 필요하지 않더라도 쿼리 옵티마이저는 이들 테이블을 모두 결합해야 합니다.내부 결합 자체가 데이터를 필터링하여 계산에 필수적인 요소가 될 수 있기 때문입니다.

이들 10개의 테이블이 외부로 결합되어 있는 경우 쿼리 옵티마이저는 실제로 필요한 테이블만 결합합니다(이 경우 10개 중 3개).이는 조인 자체가 더 이상 데이터를 필터링하지 않기 때문에 사용되지 않은 조인도 건너뛸 수 있기 때문입니다.

출처 : http://www.sqlservercentral.com/blogs/sql_coach/2010/07/29/poor-little-misunderstood-views/

성능 문제는 참가 횟수 및 참가 열에 인덱스가 있는지 여부 때문일 가능성이 높습니다.

최악의 경우 각 결합에 대해 9개의 테이블 스캔을 쉽게 수행할 수 있습니다.

내부 조인이 왼쪽 조인에 비해 빠른지 확인해보니 SQL Server에서 흥미로운 점을 발견했습니다.

왼쪽 조인 테이블의 항목을 포함하지 않으면 select 스테이트먼트에서 왼쪽 조인 속도가 내부 조인과 동일한 쿼리보다 빠릅니다.

select 문에 왼쪽 조인 테이블을 포함할 경우 동일한 쿼리를 가진 내부 조인 속도가 왼쪽 조인보다 같거나 빠릅니다.

제가 비교한 결과, 두 회사의 실행 계획은 정확히 일치합니다.세 가지 시나리오가 있습니다.

  1. 같은 결과를 반환하는 경우 및 반환되는 경우 속도는 동일합니다.단, 이 두 쿼리는 동일하지 않으며 LEFT JOIN은 (일부 ON 조건이 충족되지 않을 때) 더 많은 결과를 반환할 수 있다는 점에 유의해야 합니다.이 때문에 보통 속도가 느려집니다.

  2. 메인 테이블(실행 계획에서 처음 일정하지 않은 테이블)에 제한 조건(WHERE ID = ?)이 있고 해당 ON 조건이 NULL 값인 경우 "오른쪽" 테이블은 조인되지 않습니다. 이 경우 왼쪽 조인 속도가 더 빠릅니다.

  3. 포인트 1에서 설명한 바와 같이 보통 INSER JOIN은 더 제한적이고 더 적은 결과를 반환하므로 더 빠릅니다.

둘 다 (같은) 인덱스를 사용합니다.

언급URL : https://stackoverflow.com/questions/2726657/inner-join-vs-left-join-performance-in-sql-server

반응형