Saya mencoba untuk membujuk beberapa kinerja lagi dari permintaan yang mengakses tabel dengan ~ 250 juta catatan. Dari pembacaan saya tentang rencana pelaksanaan aktual (tidak diperkirakan), hambatan pertama adalah kueri yang terlihat seperti ini:
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;
Lihat lebih jauh ke bawah untuk definisi tabel & indeks yang terlibat.
Rencana eksekusi menunjukkan bahwa loop bersarang sedang digunakan di #smalltable, dan bahwa pemindaian indeks melalui hugetable dieksekusi 480 kali (untuk setiap baris di #smalltable). Ini kelihatannya terbalik bagi saya, jadi saya telah mencoba untuk memaksa gabungan bergabung untuk digunakan sebagai gantinya:
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;
Indeks yang dimaksud (lihat definisi lengkap di bawah) mencakup kolom fk (predikat gabungan), ditambahkan (digunakan dalam klausa where) & id (tidak berguna) dalam urutan menaik, dan termasuk nilai .
Namun, ketika saya melakukan ini, kueri meledak dari 2 1/2 menit menjadi lebih dari 9. Saya berharap bahwa petunjuk akan memaksa bergabung lebih efisien yang hanya melakukan satu melewati setiap tabel, tetapi jelas tidak.
Bimbingan apa pun diterima. Informasi tambahan disediakan jika diperlukan.
Pembaruan (2011/06/02)
Setelah mengatur ulang pengindeksan di atas meja, saya telah membuat terobosan kinerja yang signifikan, namun saya telah mengalami hambatan baru ketika meringkas data dalam tabel besar. Hasilnya adalah ringkasan berdasarkan bulan, yang saat ini terlihat seperti berikut:
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);
Saat ini, hugetable memiliki indeks berkerumun pk_hugetable (added, fk)
(kunci utama), dan indeks non-berkerumun menuju sebaliknya ix_hugetable (fk, added)
.
Tanpa kolom ke-4 di atas, pengoptimal menggunakan gabungan loop bersarang seperti sebelumnya, menggunakan #smalltable sebagai input luar, dan indeks non-cluster mencari sebagai loop dalam (mengeksekusi 480 kali lagi). Yang mengkhawatirkan saya adalah perbedaan antara baris yang diperkirakan (12.958,4) dan baris aktual (74.668.468). Biaya relatif dari upaya ini adalah 45%. Namun waktu berjalan kurang dari satu menit.
Dengan kolom ke-4, waktu berjalan meningkat menjadi 4 menit. Itu mencari pada indeks berkerumun kali ini (2 eksekusi) untuk biaya relatif yang sama (45%), agregat melalui pertandingan hash (30%), kemudian melakukan hash bergabung di #smalltable (0%).
Saya tidak yakin dengan tindakan selanjutnya. Kekhawatiran saya adalah bahwa baik pencarian rentang tanggal maupun predikat gabungan tidak dijamin atau bahkan semua yang mungkin secara drastis mengurangi set hasil. Rentang tanggal dalam kebanyakan kasus hanya akan memangkas mungkin 10-15% dari catatan, dan gabungan dalam pada fk dapat menyaring mungkin 20-30%.
Seperti yang diminta oleh Will A, hasil dari sp_spaceused
:
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltable didefinisikan sebagai:
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
Sedangkan dbo.hugetable didefinisikan sebagai:
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];
Dengan indeks berikut ditentukan:
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];
Bidang id adalah redundan, sebuah artefak dari DBA sebelumnya yang bersikeras bahwa semua tabel di mana saja harus memiliki GUID, tanpa pengecualian.