~ 2 억 5 천만 레코드로 테이블에 액세스하는 쿼리에서 더 많은 성능을 동축하려고합니다. 실제 (추정되지 않은) 실행 계획을 읽은 첫 번째 병목 현상은 다음과 같은 쿼리입니다.
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
where
a.added between @start and @end;
관련된 테이블 및 인덱스의 정의는 아래를 참조하십시오.
실행 계획은 중첩 루프가 #smalltable에서 사용되고 있고 hugetable에 대한 인덱스 스캔이 480 번 (#smalltable의 각 행에 대해) 실행되고 있음을 나타냅니다. 이것은 거꾸로 보이므로 병합 조인을 대신 사용하려고했습니다.
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a with(index = ix_hugetable)
inner merge join
#smalltable b with(index(1)) on a.fk = b.pk
where
a.added between @start and @end;
문제의 인덱스 (아래의 전체 정의는 참조)는 열 fk (결합 조인), 추가 (where 절에서 사용됨) 및 id (무효)를 오름차순으로 포함하며 value를 포함 합니다 .
그러나이 작업을 수행하면 쿼리가 2 1/2 분에서 9 이상으로 폭발합니다. 힌트를 사용하면 각 테이블을 한 번만 통과하는보다 효율적인 조인이 더 효율적으로 이루어 지길 바랍니다.
모든 안내를 환영합니다. 필요한 경우 추가 정보가 제공됩니다.
업데이트 (2011/06/02)
테이블에서 인덱싱을 재구성 한 후 성능이 크게 향상되었지만 거대한 테이블의 데이터를 요약 할 때 새로운 장애물에 부딪 쳤습니다. 결과는 월별 요약이며 현재 다음과 같습니다.
select
b.stuff,
datediff(month, 0, a.added),
count(a.value),
sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
group by
b.stuff,
datediff(month, 0, a.added);
현재 hugetable 에는 클러스터형 인덱스 pk_hugetable (added, fk)
(기본 키)와 클러스터되지 않은 인덱스가 ix_hugetable (fk, added)
있습니다.
위의 네 번째 열이 없으면 옵티마이 저는 이전과 같이 중첩 입력 조인을 사용합니다. #smalltable을 외부 입력으로 사용하고 비 클러스터형 인덱스 검색을 내부 루프로 사용합니다 (다시 480 번 실행). 나에게 중요한 것은 예상 행 (12,958.4)과 실제 행 (74,668,468) 사이의 불일치입니다. 이러한 탐색의 상대 비용은 45 %입니다. 그러나 실행 시간은 1 분 미만입니다.
네 번째 열에서는 실행 시간이 4 분으로 급증합니다. 이번에는 동일한 상대 비용 (45 %)으로 클러스터 된 인덱스를 검색 (2 회 실행)하고 해시 일치 (30 %)를 통해 집계 한 다음 #smalltable (0 %)에서 해시 조인을 수행합니다.
다음 행동에 대해서는 확신이 없습니다. 내 관심사는 날짜 범위 검색이나 조인 술어가 보장되지 않거나 결과 집합을 크게 줄일 가능성이 없다는 것입니다. 대부분의 경우 날짜 범위는 레코드의 10-15 % 만 다듬고 fk 의 내부 조인은 20-30 %를 필터링 할 수 있습니다.
Will A가 요청한 결과는 sp_spaceused
다음 과 같습니다.
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltable 은 다음과 같이 정의됩니다.
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
하지만 dbo.hugetable는 다음과 같이 정의된다
create table dbo.hugetable (
id uniqueidentifier not null,
fk uniqueidentifier not null,
added datetime not null,
value decimal(13, 3) not null,
constraint pk_hugetable primary key clustered (
fk asc,
added asc,
id asc
)
with (
pad_index = off, statistics_norecompute = off,
ignore_dup_key = off, allow_row_locks = on,
allow_page_locks = on
)
on [primary]
)
on [primary];
다음 색인이 정의되어 있습니다.
create nonclustered index ix_hugetable on dbo.hugetable (
fk asc, added asc, id asc
) include(value) with (
pad_index = off, statistics_norecompute = off,
sort_in_tempdb = off, ignore_dup_key = off,
drop_existing = off, online = off,
allow_row_locks = on, allow_page_locks = on
)
on [primary];
아이디 필드 주장 이전 DBA에서 인공물 중복 모든 테이블이 사방 GUID, 예외없이이 있어야합니다.