9 테이블에서 INNER JOIN을 사용하는 SQL 명령을 만들었습니다. 어쨌든이 명령은 매우 오랜 시간 (5 분 이상)이 걸립니다. 그래서 내 사람들은 내가 알고 있더라도 LEFT JOIN의 성능이 더 좋기 때문에 INNER JOIN을 LEFT JOIN으로 변경하도록 제안했습니다. 변경 후 쿼리 속도가 크게 향상되었습니다.
LEFT JOIN이 INNER JOIN보다 빠른 이유를 알고 싶습니다.
아래처럼 내 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
결과를 널 확장하는 추가 작업과 추가 작업을 모두 수행해야합니다 . 또한 더 많은 행을 반환하여 결과 집합의 크기가 커서 총 실행 시간이 더 늘어날 것으로 예상됩니다.
(그리고 상상하기 어려운 요인의 합류로 인해 특정 상황 에서 a LEFT JOIN
가 빠르 더라도 기능적으로 a와 동일 하지 않으므로 한 인스턴스의 모든 인스턴스를 다른 인스턴스로 간단히 바꿀 수는 없습니다!)INNER JOIN
후보 키나 외래 키가 제대로 색인되지 않은 등 성능 문제가 다른 곳에있을 가능성이 높습니다. 9 개의 테이블은 조인해야 할 것이 많기 때문에 속도 저하가 문자 그대로 거의 어디에나있을 수 있습니다. 스키마를 게시하면 자세한 내용을 제공 할 수 있습니다.
편집하다:
이것에 더 반영하여, 나는 a 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
버전은 클러스터 된 인덱스 스캔 중 하나를 탐색으로 대체 할 수 있습니다. 즉, 이는 많은 행에서 문자 그대로 10 배 더 빠릅니다.
결론은 위의 여러 단락에서 언급 한 것입니다. 이것은 거의 확실하게 하나 이상의 작은 테이블과 결합 된 인덱싱 또는 인덱스 적용 범위 문제입니다. 이러한 상황은 SQL Server 가 때때로 INNER JOIN
보다 나은 실행 계획을 선택할 수 있는 유일한 환경 LEFT JOIN
입니다.
답변
아직 논의되지 않은 내부 조인보다 외부 조인이 더 빠를 수있는 중요한 시나리오가 있습니다.
외부 조인을 사용할 때 조인 열이 외부 테이블의 PK이고 외부 테이블 열이 외부 조인 자체 외부에서 참조되지 않는 경우 옵티마이 저는 항상 실행 계획에서 외부 조인 테이블을 삭제할 수 있습니다. 예를 들어 SELECT A.* FROM A LEFT OUTER JOIN B ON A.KEY=B.KEY
B.KEY는 B의 PK입니다. 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에서 내부 조인을 어떻게 능가하는지 쉽게 알 수 있습니다.
이것은 간단한 예이며 독립형 쿼리에는 실용적이지 않습니다. 필요하지 않은 이유는 무엇입니까?
그러나 이것은 뷰를 설계 할 때 매우 중요한 설계 고려 사항이 될 수 있습니다. 중앙 테이블과 관련하여 사용자가 필요로하는 모든 것을 결합하는 “모든 것”뷰가 자주 만들어집니다. (특히 관계형 모델을 이해하지 못하는 임시 쿼리를 수행하는 순진한 사용자가있는 경우)보기에는 많은 테이블의 모든 관련 열이 포함될 수 있습니다. 그러나 최종 사용자는 뷰 내의 테이블 하위 집합의 열에 만 액세스 할 수 있습니다. 테이블이 외부 조인으로 조인 된 경우 옵티마이 저는 필요하지 않은 테이블을 계획에서 삭제할 수 있습니다.
외부 조인을 사용하는 뷰가 올바른 결과를 제공하는지 확인하는 것이 중요합니다. Aaronaught가 말했듯이-OUTER JOIN을 INNER JOIN으로 맹목적으로 대체 할 수 없으며 동일한 결과를 기대할 수 있습니다. 그러나 뷰를 사용할 때 성능상의 이유로 유용 할 수있는 경우가 있습니다.
마지막 참고 사항-위의 관점에서 성능에 미치는 영향을 테스트하지는 않았지만 이론적으로 <FOREIGN_KEY> IS NULL이 아닌 조건을 추가하면 INNER JOIN을 OUTER JOIN으로 안전하게 바꿀 수 있어야합니다 where 절에.
답변
모든 것이 제대로 작동하지 않으면 쿼리 최적화 프로그램, 쿼리 계획 캐싱 및 통계와 관련하여 모든 것이 제대로 작동하지 않는다는 것을 알고 있습니다.
먼저 인덱스와 통계를 재구성 한 다음 쿼리 계획 캐시를 지우면 문제가 해결되지 않습니다. 그러나 나는 그것이 끝났어도 문제가 발생했습니다.
왼쪽 조인이 내부 조인보다 빠른 경우를 경험했습니다.
기본 이유는 다음과 같습니다. 두 개의 테이블이 있고 인덱스가있는 열 (두 테이블 모두)에 조인하는 경우. 내부 조인은 테이블 1의 인덱스에있는 항목을 반복하고 테이블 2의 인덱스와 일치하는 경우에도 반대의 경우와 동일한 결과를 생성합니다. 표 1에서. 문제는 잘못된 통계가있을 경우 쿼리 최적화 프로그램이 인덱스 통계를 사용하여 일치하는 항목이 가장 적은 테이블을 찾습니다 (다른 기준에 따라). 각각 100 만 개의 테이블이 두 개있는 경우 테이블 1에는 10 개의 행이 일치하고 테이블 2에는 100000 개의 행이 있습니다. 가장 좋은 방법은 테이블 1에서 인덱스 스캔을 수행하고 테이블 2에서 10 번 일치하는 것입니다. 그 반대의 경우에는 100000 개가 넘는 행을 반복하고 100000 회 일치 시키려고하지만 10 개만 성공하는 인덱스 스캔입니다. 따라서 통계가 정확하지 않으면 옵티마이 저가 잘못된 테이블과 인덱스를 선택하여 루프 오버 할 수 있습니다.
옵티마이 저가 작성된 순서대로 왼쪽 조인을 최적화하기로 선택하면 내부 조인보다 성능이 우수합니다.
그러나 옵티마이 저는 왼쪽 반 결합으로서 왼쪽 결합을 차선 최적화 할 수도 있습니다. 원하는 것을 선택하기 위해 강제 순서 힌트를 사용할 수 있습니다.
답변
OPTION (FORCE ORDER)
끝에 두 개의 쿼리 (내부 및 왼쪽 조인이있는 쿼리)를 모두 시도 하고 결과를 게시하십시오. OPTION (FORCE ORDER)
는 쿼리에서 제공 한 조인 순서로 옵티마이 저가 실행 계획을 작성하도록하는 쿼리 힌트입니다.
INNER JOIN
로 빠른 수행을 시작 하면 다음 과 같은 LEFT JOIN
이유 때문입니다.
- 전적으로
INNER JOIN
s 로 구성된 쿼리 에서 조인 순서는 중요하지 않습니다. 따라서 쿼리 최적화 프로그램이 조인을 적절하게 표시 할 수 있도록 조인을 자유롭게 주문할 수 있으므로 문제는 최적화 프로그램에 의존 할 수 있습니다. - 와
LEFT JOIN
(가) 쿼리의 결과를 바꿀 것 조인 순서를 변경하기 때문에 그렇지 않다 그. 이는 엔진이 쿼리에서 제공 한 조인 순서를 따라야한다는 것을 의미하며 이는 최적화 된 것보다 낫습니다.
이것이 귀하의 질문에 대답하는지 모르겠지만 한 번은 계산을하는 매우 복잡한 쿼리를 특징으로하는 프로젝트에 있었고 최적화 프로그램을 완전히 엉망으로 만들었습니다. 우리는 FORCE ORDER
쿼리 실행 시간을 5 분에서 10 초로 줄이는 경우가있었습니다 .
답변
왼쪽 외부 및 내부 조인을 여러 번 비교했지만 구성된 차이를 찾을 수 없었습니다. 많은 변수가 있습니다. 많은 필드가 있고 시간이 지남에 따라 많은 변경 사항 (공급 업체 버전 및 로컬 워크 플로)이있는 수천 개의 테이블이있는보고 데이터베이스에서 작업하고 있습니다. 이러한 다양한 쿼리의 요구를 충족하고 히스토리 데이터를 처리하기 위해 인덱스를 포함하는 모든 조합을 작성할 수는 없습니다. 많은 수의 필드를 가져오고 커버링 인덱스가 존재하지 않는 두 개의 큰 (수백만에서 수억 행) 테이블이 내부 결합되어 내부 쿼리가 서버 성능을 저하시키는 것으로 나타났습니다.
그러나 가장 큰 문제는 위의 토론에서 더 좋아 보이지는 않습니다. 데이터베이스는 트리거가 잘 설계되고 트랜잭션 처리가 잘 설계되어 올바른 데이터를 보장 할 수 있습니다. 광산에는 종종 예상치 못한 NULL 값이 있습니다. 예, 테이블 정의는 널이 아닌 것을 강제 할 수 있지만 내 환경에서는 옵션이 아닙니다.
따라서 질문은 … 분당 수천 번 동일한 코드를 실행하는 트랜잭션 처리의 우선 순위가 빠른 속도로만 쿼리를 설계합니까? 또는 왼쪽 외부 조인이 제공하는 정확성을 원하십니까? 내부 조인은 양쪽에서 일치하는 항목을 찾아야하므로 예기치 않은 NULL은 두 테이블에서 데이터를 제거 할뿐만 아니라 전체 정보 행을 제거합니다. 그리고 오류 메시지가 전혀 발생하지 않습니다.
필요한 데이터의 90 %를 가져오고 내부 조인이 정보를 자동으로 제거함을 발견하지 못해 매우 빠릅니다. 때로는 내부 조인이 더 빠를 수 있지만 실행 계획을 검토하지 않는 한 누구도 그 가정을 믿지 않습니다. 속도는 중요하지만 정확성이 더 중요합니다.
답변
수행중인 조인 수와 조인중인 열에 색인이 있는지 여부로 인해 성능 문제가 발생하기 쉽습니다.
최악의 경우 각 조인에 대해 9 개의 전체 테이블 스캔을 쉽게 수행 할 수 있습니다.
답변
외부 조인은 뷰에서 사용될 때 우수한 성능을 제공 할 수 있습니다.
뷰가 포함 된 쿼리가 있고 해당 뷰가 10 개의 테이블이 결합되어 있다고 가정 해 봅시다. 쿼리에서 10 개의 테이블 중 3 개의 열만 사용한다고 가정 해보십시오.
이 10 개의 테이블이 함께 결합 된 경우 쿼리 자체에 테이블 중 10 개 중 7 개가 필요하지 않더라도 쿼리 최적화 프로그램이 테이블을 모두 조인해야합니다. 내부 조인 자체가 데이터를 필터링하여 계산에 필수적 일 수 있기 때문입니다.
이 10 개의 테이블이 대신 외부 조인 된 경우 쿼리 최적화 프로그램은 실제로 필요한 테이블 만 조인합니다 (이 경우 10 개 중 3 개). 조인 자체가 더 이상 데이터를 필터링하지 않기 때문에 사용하지 않는 조인을 건너 뛸 수 있기 때문입니다.
출처 :
http://www.sqlservercentral.com/blogs/sql_coach/2010/07/29/poor-little-misunderstood-views/