Saya perhatikan bahwa ketika ada tumpahan ke acara tempdb (menyebabkan kueri lambat) yang sering kali perkiraan baris jauh dari gabungan tertentu. Saya telah melihat peristiwa tumpahan terjadi dengan menggabungkan dan hash bergabung dan mereka sering meningkatkan runtime 3x menjadi 10x. Pertanyaan ini menyangkut bagaimana meningkatkan perkiraan baris dengan asumsi bahwa hal itu akan mengurangi kemungkinan peristiwa tumpahan.
Jumlah baris sebenarnya 40k.
Untuk kueri ini, paket menampilkan taksiran baris buruk (11,3 baris):
select Value
from Oav.ValueArray
where ObjectId = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
Untuk kueri ini, paket menampilkan estimasi baris yang bagus (baris 56rb):
declare @a bigint = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2);
select Value
from Oav.ValueArray
where ObjectId = @a
and PropertyId = 2840
option (recompile);
Dapatkah statistik atau petunjuk ditambahkan untuk meningkatkan perkiraan baris untuk kasus pertama? Saya mencoba menambahkan statistik dengan nilai filter tertentu (properti = 2840) tetapi tidak bisa mendapatkan kombinasi yang benar atau mungkin diabaikan karena ObjectId tidak diketahui pada waktu kompilasi dan mungkin memilih rata-rata di atas semua ObjectIds.
Apakah ada mode di mana ia akan melakukan penyelidikan terlebih dahulu dan kemudian menggunakannya untuk menentukan estimasi baris atau haruskah terbang secara membabi buta?
Properti khusus ini memiliki banyak nilai (40k) pada beberapa objek dan nol pada sebagian besar. Saya akan senang dengan petunjuk di mana jumlah baris maksimum yang diharapkan untuk suatu join dapat ditentukan. Ini adalah masalah yang umumnya menghantui karena beberapa parameter dapat ditentukan secara dinamis sebagai bagian dari gabungan atau akan lebih baik ditempatkan dalam tampilan (tidak ada dukungan untuk variabel).
Apakah ada parameter yang dapat disesuaikan untuk meminimalkan kemungkinan tumpahan ke tempdb (mis. Memori min per kueri)? Rencana yang kuat tidak berpengaruh pada estimasi.
Edit 2013.11.06 : Tanggapan terhadap komentar dan informasi tambahan:
Berikut adalah gambar rencana kueri. Peringatannya adalah tentang kardinalitas / mencari predikat dengan orang yang dipertobatkan ():
Per komentar @Aaron Bertrand, saya mencoba mengganti convert () sebagai tes:
create table Oav.SeekObject (
LookupId bigint not null primary key,
ObjectId bigint not null
);
insert into Oav.SeekObject (
LookupId, ObjectId
) VALUES (
1, 3540233
)
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.SeekObject
where LookupId = 1)
and PropertyId = 2840
option (recompile);
Sebagai tempat tujuan yang aneh namun berhasil, juga memungkinkannya untuk menyingkat pencarian:
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.ValueArray
where PropertyId = 2840
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
Kedua daftar ini pencarian kunci yang tepat tetapi hanya yang pertama daftar "Output" dari ObjectId. Saya kira itu menunjukkan yang kedua memang korsleting?
Dapatkah seseorang memverifikasi apakah penyelidikan baris tunggal pernah dilakukan untuk membantu dengan perkiraan baris? Tampaknya salah untuk membatasi pengoptimalan hanya perkiraan histogram ketika pencarian PK baris tunggal dapat sangat meningkatkan akurasi pencarian ke dalam histogram (terutama jika ada potensi tumpahan atau riwayat). Ketika ada 10 sub-gabungan ini dalam kueri nyata, idealnya mereka akan terjadi secara paralel.
Catatan tambahan, karena sql_variant menyimpan tipe dasarnya (SQL_VARIANT_PROPERTY = BaseType) di dalam isian itu sendiri, saya akan mengharapkan konversi () hampir tanpa biaya asalkan konversi "langsung" (mis. Bukan string ke desimal tetapi bukan int ke int atau mungkin int ke bigint). Karena itu tidak diketahui pada waktu kompilasi tetapi dapat diketahui oleh pengguna, mungkin fungsi "AssumeType (type, ...)" untuk sql_variants akan memungkinkan mereka diperlakukan lebih transparan.
declare @a bigint =
seperti yang Anda lakukan tampaknya merupakan solusi alami bagi saya, mengapa itu tidak dapat diterima?
CONVERT()
kolom dan kemudian bergabung dengan mereka. Ini tentu tidak efisien dalam banyak kasus. Dalam yang khusus ini, hanya satu nilai yang akan dikonversi jadi itu mungkin bukan masalah tetapi indeks apa yang Anda miliki di atas meja? Desain EAV biasanya berkinerja baik, hanya dengan pengindeksan yang tepat (yang berarti banyak indeks dalam tabel yang biasanya sempit).