~ 250 milyon kayıtları olan bir tabloya erişen bir sorgudan biraz daha fazla performans koaksiyelim. Gerçek (tahmin edilmeyen) yürütme planını okuduğumdan, ilk darboğaz şuna benzeyen bir sorgu:
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;
İlgili tabloların ve dizinlerin tanımları için aşağıya bakınız.
Yürütme planı, #smalltable üzerinde iç içe bir döngü kullanıldığını ve devasa tablo üzerinden dizin taramasının 480 kez yürütüldüğünü gösterir (#smalltable içindeki her satır için). Bu bana geriye doğru görünüyor, bu yüzden bunun yerine birleştirme birleşimini kullanmaya zorladım:
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;
Söz konusu dizin (tam tanım için aşağıya bakın ), artan sırada fk (birleştirme yüklemi), eklenen (nerede yan tümcesinde kullanılır) & id (yararsız) sütunlarını kapsar ve değer içerir .
Ancak, bunu yaptığımda, sorgu 2 1/2 dakika 9 üzerinden patlar. Ben ipuçları her tablo üzerinde tek bir geçiş yapar, ancak açıkça değil, daha verimli bir birleşim zorlamak umuyordum.
Herhangi bir rehberlik bekliyoruz. Gerekirse ek bilgi sağlanır.
Güncelleme (2011/06/02)
Tablodaki endekslemeyi yeniden düzenledikten sonra, önemli performanslar elde ettim, ancak büyük tablodaki verileri özetlemek için yeni bir engele çarptım. Sonuç, şu anda aşağıdaki gibi görünen aylara göre bir özettir:
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);
Şu anda, devasa dizinin kümelenmiş bir dizini pk_hugetable (added, fk)(birincil anahtar) ve kümelenmemiş bir dizini diğer yöne gidiyor ix_hugetable (fk, added).
Yukarıdaki 4. sütun olmadan, iyileştirici dış giriş olarak # küçük harf kullanarak ve iç döngü olarak kümelenmemiş bir dizin araması kullanarak (480 kez tekrar yürütülür) iç içe geçmiş bir döngü birleşimi kullanır. Beni ilgilendiren, tahmini satırlar (12.958.4) ile gerçek satırlar (74.668.468) arasındaki eşitsizliktir. Bu aramaların göreceli maliyeti% 45'tir. Ancak çalışma süresi bir dakikadan azdır.
4. sütun ile çalışma süresi 4 dakikaya yükselir. Bu sefer kümelenmiş endeksi (2 yürütme) aynı göreceli maliyet (% 45) için arar, bir karma eşleşmesi (% 30) yoluyla toplanır, sonra #smalltable (% 0) üzerinde bir karma birleştirme yapar.
Bir sonraki eylemimden emin değilim. Benim endişem, ne tarih aralığı araması ne de birleştirme tahmini garanti edilmez, hatta sonuç kümesini büyük ölçüde azaltabilecek olanların hepsi. Çoğu durumda tarih aralığı, kayıtların yalnızca% 10-15'ini keser ve fk'deki iç bağlantı belki% 20-30'u filtreleyebilir.
Will A tarafından talep edildiği gibi, sonuçları sp_spaceused:
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltable şu şekilde tanımlanır:
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
İken dbo.hugetable olarak tanımlanır:
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];
Aşağıdaki dizin tanımlandığında:
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];
İd alanı, ısrarla bir önceki DBA ait bir eserdir gereksiz tüm tabloları her yerde bir GUID, hiçbir istisna olmalıdır.