나는 천천히 매우 실행이 쿼리 (거의 분)이 있습니다이유는 하나 개의 쿼리가 매우 느린 유사한 테이블에 아직 동일한 쿼리가 눈 깜짝 할 사이에 실행됩니다
select distinct main.PrimeId
from PRIME main
join
(
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId or p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
) mem
on main.PrimeId = mem.PrimeId
국무 테이블을 18k 행을 가지며 PrimeId에 PK가 있습니다.
ATTRGROUP 테이블은 24k 개의 행을 가지며 PrimeId, col2, RelatedPrimeId 및 복합 4-7의 복합 PK를가집니다. RelatedPrimeId에는 별도의 색인도 있습니다. ATTRGROUP 대신 ATTRADDRESS를 사용하여, 나는 동일한 쿼리를 가지고있는 ATTRGROUP 테이블
에 PrimeId 또는 RelatedPrimeId 중 하나와 일치하는 PRIME 테이블에 PrimeId의 고유 값 -
은쿼리는 결국 8.5k 행을 반환합니다. ATTRADDRESS는 ATTRGROUP과 동일한 키 W 색인 구조를가집니다. 그것은 단지 11k 행을 가지는데, 그보다는 더 작지만,이 경우 쿼리는 약 1 초 만에 실행되고 11k 행을 반환합니다.
그래서 제 질문은 이것이다 :
어떻게 쿼리가 동일한되는 구조에도 불구하고, 다른 것보다 하나 개의 테이블에 훨씬 느려질 수 있습니다.
지금까지 SQL 2005에서 (동일한 데이터베이스를 사용하여 업그레이드 한) SQL 2008 R2를 사용해 보았습니다. 우리 중 두 명은 동일한 결과를 두 개의 다른 컴퓨터에 독립적으로 복원하여 독립적으로 얻었습니다.
기타 사항 :
- 대괄호 내의 비트는 이해가 안 실행 계획에 가능한 단서가에도 느린 쿼리
- 에, 초 미만에서 실행됩니다. 여기의 부분은 의심스러운 320000000 행 조작으로,이다 :
그러나, 그 테이블에 행의 실제 수는 320M, 24K 이상 조금 아닙니다! 그것이 OR보다는 UNION을 사용하도록
나는 따라서, 대괄호 내의 쿼리의 일부를 리팩토링하는 경우 :
select distinct main.PrimeId
from PRIME main
join
(
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
UNION
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
) mem
on main.PrimeId = mem.PrimeId
은 ... 다음 느린 쿼리는 초 정도 소요됩니다.
나는 이것에 대한 통찰력을 크게 주셔서 감사합니다! 더 자세한 정보가 필요하면 알려 주시면 질문을 업데이트하겠습니다. 감사!
그런데이 예제에서 중복 가입이 있음을 알고 있습니다. 프로덕션에서는 모든 것이 동적으로 생성되고 괄호 안의 비트는 여러 가지 양식을 사용하기 때문에 쉽게 제거 할 수 없습니다.
편집 : 나는 ATTRGROUP에 인덱스를 재 구축 한
는 유의 한 차이가 없습니다.
편집 2 :
나는 따라서 임시 테이블을 사용하는 경우 :
select distinct p.PrimeId into #temp
from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId or p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
select distinct main.PrimeId
from Prime main join
#temp mem
on main.PrimeId = mem.PrimeId
... 다시 원래 OUTER의 OR은 가입도 함께, 그것은 이하에서 실행을 초. 나는 임시 테이블을 싫어한다, 왜냐하면 항상 패배를 인정하는 것 같기 때문에 내가 사용할 리팩터링이 아니지만 그런 차이가 있다는 것이 흥미 롭다.
편집 3 : 통계를 업데이트
중 하나 차이가 없습니다.
지금까지 의견을 보내 주셔서 감사합니다.
정말 좋은 질문입니다! –
@ 루이즈 : 왜 그런 말을하니? –
18K * 24K는 432M입니다. 320M의 야구장에서. 우연의 일치 일지 모르지만, 어쩌면 보일만한 곳일지도 모릅니다. –