TL; DR
이 질문은 계속 견해를 가지고 있기 때문에 여기에 요약하여 새로 온 사람들이 역사를 겪지 않아도되도록합니다.
JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1, @value2) -- this is blazing fast
-- Note that here if @value1 has a value, @value2 is NULL, and vice versa
나는 이것이 모든 사람의 문제가 아니라는 것을 알고 있지만 ON 절의 감도를 강조함으로써 올바른 방향을 찾는 데 도움이 될 수 있습니다. 어쨌든 원문은 미래 인류학자를위한 것입니다.
원문
다음과 같은 간단한 쿼리를 고려하십시오 (3 개의 테이블 만 관련됨)
SELECT
l.sku_id AS ProductId,
l.is_primary AS IsPrimary,
v1.category_name AS Category1,
v2.category_name AS Category2,
v3.category_name AS Category3,
v4.category_name AS Category4,
v5.category_name AS Category5
FROM category c4
JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'
JOIN category c3 ON c3.category_id = c4.parent_category_id
JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'
JOIN category c2 ON c2.category_id = c3.category_id
JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'
JOIN category c1 ON c1.category_id = c2.parent_category_id
JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'
LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang
JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
l.category_id = c4.category_id OR
l.category_id = c5.category_id
)
WHERE c4.[level] = 4 AND c4.version_id = 5
이것은 매우 간단한 쿼리이며 혼란스러운 부분은 마지막 범주 조인입니다. 범주 수준 5가 존재하거나 존재하지 않을 수 있기 때문에 이런 식입니다. 쿼리가 끝날 때마다 제품 ID (SKU ID) 당 범주 정보를 찾고 있는데, 이것이 매우 큰 테이블 category_link가 나오는 곳입니다. 마지막으로, 테이블 #Ids는 10'000 ID를 포함하는 임시 테이블입니다.
실행되면 다음과 같은 실제 실행 계획이 나타납니다.
보시다시피, 거의 90 %의 시간이 중첩 루프 (내부 조인)에 사용됩니다. 중첩 루프에 대한 추가 정보는 다음과 같습니다.
가독성을 위해 쿼리 테이블 이름을 편집했기 때문에 테이블 이름이 정확히 일치하지는 않지만 일치하기 쉽습니다 (ads_alt_category = category). 이 쿼리를 최적화 할 수있는 방법이 있습니까? 또한 프로덕션에는 임시 테이블 #Id가 존재하지 않고 저장 프로 시저에 전달 된 동일한 10,000 ID의 테이블 값 매개 변수입니다.
추가 정보:
- category_id 및 parent_category_id의 범주 인덱스
- category_id, language_code의 category_voc 색인
- sku_id, category_id의 category_link 색인
편집 (해결)
허용 된 답변에서 지적한 것처럼 문제는 category_link JOIN의 OR 절이었습니다. 그러나 허용 된 답변에서 제안 된 코드는 원래 코드보다 매우 느리고 느립니다. 훨씬 빠르고 깨끗한 솔루션은 현재 JOIN 조건을 다음과 같이 바꾸는 것입니다.
JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id, c4.category_id)
이 미세 조정은 가장 빠른 솔루션이며, 허용 된 답변의 이중 결합에 대해 테스트되었으며 valverij에서 제안한대로 CROSS APPLY에 대해서도 테스트되었습니다.