Saya mengalami situasi aneh di mana menambahkan OPTION (RECOMPILE)
permintaan saya menyebabkannya berjalan dalam setengah detik, sementara menghilangkannya menyebabkan permintaan mengambil lebih dari lima menit.
Ini adalah kasus ketika kueri dieksekusi dari Query Analyzer atau dari program C # saya via SqlCommand.ExecuteReader()
. Memanggil (atau tidak menelepon) DBCC FREEPROCCACHE
atau DBCC dropcleanbuffers
tidak ada bedanya; Hasil kueri selalu dikembalikan secara instan dengan OPTION (RECOMPILE)
dan lebih dari lima menit tanpanya. Kueri selalu dipanggil dengan parameter yang sama [demi pengujian ini].
Saya menggunakan SQL Server 2008.
Saya cukup nyaman dengan menulis SQL tetapi tidak pernah menggunakan OPTION
perintah dalam permintaan sebelumnya dan tidak terbiasa dengan seluruh konsep cache rencana sampai memindai posting di forum ini. Pemahaman saya dari posting adalah bahwa itu OPTION (RECOMPILE)
adalah operasi yang mahal. Tampaknya menciptakan strategi pencarian baru untuk kueri. Jadi mengapa kemudian, bahwa pertanyaan selanjutnya yang menghilangkan OPTION (RECOMPILE)
begitu lambat? Tidakkah seharusnya pertanyaan selanjutnya menggunakan strategi pencarian yang dihitung pada panggilan sebelumnya yang termasuk petunjuk kompilasi?
Apakah sangat tidak biasa memiliki permintaan yang memerlukan petunjuk kompilasi pada setiap panggilan tunggal?
Maaf untuk pertanyaan entry-level tapi saya tidak bisa benar-benar membuat kepala atau ekor dari ini.
UPDATE: Saya telah diminta untuk mengirim kueri ...
select acctNo,min(date) earliestDate
from(
select acctNo,tradeDate as date
from datafeed_trans
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_money
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_jnl
where feedid=@feedID and feedDate=@feedDate
)t1
group by t1.acctNo
OPTION(RECOMPILE)
Saat menjalankan tes dari Query Analyzer, saya menambahkan baris berikut:
declare @feedID int
select @feedID=20
declare @feedDate datetime
select @feedDate='1/2/2009'
Saat memanggilnya dari program C # saya, parameter dilewatkan melalui SqlCommand.Parameters
properti.
Untuk keperluan diskusi ini, Anda dapat mengasumsikan bahwa parameter tidak pernah berubah sehingga kami dapat mengesampingkan parameter yang berbau tidak optimal sebagai penyebabnya.
sumber
X = @X OR @X IS NULL
keX=@X
dan melakukan pencarian Lihat di sini atau mendorong predikat lebih jauh terhadap tampilan dengan fungsi jendelaRECOMPILE
. Dalam setiap kejadian, tangkap rencana eksekusi dan lihat perbedaannya.Jawaban:
Ada kalanya menggunakan itu
OPTION(RECOMPILE)
masuk akal. Dalam pengalaman saya satu-satunya waktu ini adalah opsi yang layak adalah ketika Anda menggunakan SQL dinamis. Sebelum Anda menjelajahi apakah ini masuk akal dalam situasi Anda, saya akan merekomendasikan membangun kembali statistik Anda. Ini dapat dilakukan dengan menjalankan yang berikut ini:Dan kemudian menciptakan kembali rencana eksekusi Anda. Ini akan memastikan bahwa ketika rencana eksekusi Anda dibuat, itu akan menggunakan informasi terbaru.
Menambahkan
OPTION(RECOMPILE)
membangun kembali paket eksekusi setiap kali query Anda dieksekusi. Saya belum pernah mendengar yang digambarkan sebagaicreates a new lookup strategy
tetapi mungkin kita hanya menggunakan istilah yang berbeda untuk hal yang sama.Ketika prosedur tersimpan dibuat (saya curiga Anda memanggil ad-hoc sql dari. NET tetapi jika Anda menggunakan kueri parameterisasi maka ini berakhir dengan panggilan proc tersimpan ) SQL Server berupaya menentukan rencana eksekusi paling efektif untuk kueri ini berdasarkan data dalam database Anda dan parameter yang dilewatkan ( parameter sniffing ), dan kemudian cache rencana ini. Ini berarti bahwa jika Anda membuat kueri di mana ada 10 catatan dalam basis data Anda dan kemudian jalankan ketika ada 100.000.000 catatan, rencana pelaksanaan yang di-cache mungkin tidak lagi paling efektif.
Singkatnya - saya tidak melihat alasan apa pun yang
OPTION(RECOMPILE)
akan bermanfaat di sini. Saya menduga Anda hanya perlu memperbarui statistik dan rencana eksekusi Anda. Membangun kembali statistik dapat menjadi bagian penting dari pekerjaan DBA tergantung pada situasi Anda. Jika Anda masih mengalami masalah setelah memperbarui statistik Anda, saya sarankan memposting kedua rencana eksekusi.Dan untuk menjawab pertanyaan Anda - ya, saya akan mengatakan sangat tidak biasa untuk opsi terbaik Anda untuk mengkompilasi ulang rencana eksekusi setiap kali Anda mengeksekusi query.
sumber
OPTION (RECOMPILE)
mungkin satu-satunya solusi.Seringkali ketika ada perbedaan drastis dari menjalankan ke menjalankan kueri saya menemukan bahwa itu sering salah satu dari 5 masalah.
STATISTIK- Statistik kedaluwarsa. Database menyimpan statistik pada rentang dan distribusi jenis nilai dalam berbagai kolom pada tabel dan indeks. Ini membantu mesin kueri untuk mengembangkan "Rencana" serangan untuk bagaimana ia akan melakukan kueri, misalnya jenis metode yang akan digunakan untuk mencocokkan kunci antara tabel menggunakan hash atau melihat seluruh set. Anda dapat memanggil Perbarui Statistik di seluruh database atau hanya tabel atau indeks tertentu. Ini memperlambat kueri dari satu run ke run lain karena ketika statistik kedaluwarsa, kemungkinan rencana kueri tidak optimal untuk data yang baru dimasukkan atau diubah untuk kueri yang sama (dijelaskan lebih lanjut di bawah). Mungkin tidak tepat untuk Memperbarui Statistik segera pada basis data Produksi karena akan ada beberapa overhead, memperlambat dan lag tergantung pada jumlah data untuk sampel. Anda juga dapat memilih untuk menggunakan Pemindaian Lengkap atau Pengambilan Sampel untuk memperbarui Statistik. Jika Anda melihat Rencana Kueri, Anda kemudian dapat juga melihat statistik pada Indeks yang digunakan seperti menggunakan perintahDBCC SHOW_STATISTICS (nama tab, nama indeks) . Ini akan menunjukkan kepada Anda distribusi dan rentang kunci yang digunakan rencana kueri untuk mendasarkan pendekatannya.
PARAMETER SNIFFING - Rencana kueri yang di-cache tidak optimal untuk parameter tertentu yang Anda lewati, meskipun kueri itu sendiri belum berubah. Misalnya, jika Anda memasukkan parameter yang hanya mengambil 10 dari 1.000.000 baris, maka paket kueri yang dibuat dapat menggunakan Hash Join, namun jika parameter yang Anda lewati akan menggunakan 750.000 dari 1.000.000 baris, paket yang dibuat mungkin merupakan pemindaian indeks atau pemindaian tabel. Dalam situasi seperti itu Anda bisa memberi tahu pernyataan SQL untuk menggunakan opsi OPTION (RECOMPILE) atau SP untuk menggunakan WITH RECOMPILE. Untuk memberi tahu Engine ini "Rencana Penggunaan Tunggal" dan tidak menggunakan Rencana Cached yang kemungkinan tidak berlaku. Tidak ada aturan tentang bagaimana membuat keputusan ini, itu tergantung pada mengetahui cara kueri akan digunakan oleh pengguna.
INDEKS - Kemungkinan bahwa kueri belum berubah, tetapi perubahan di tempat lain seperti penghapusan indeks yang sangat berguna telah memperlambat kueri.
ROWS CHANGED - Baris yang Anda tanyakan berubah secara drastis dari panggilan ke panggilan. Biasanya statistik diperbarui secara otomatis dalam kasus ini. Namun, jika Anda sedang membangun SQL dinamis atau memanggil SQL dalam loop ketat, ada kemungkinan Anda menggunakan Rencana Kueri yang kedaluwarsa berdasarkan jumlah baris atau statistik yang drastis. Lagi-lagi dalam hal ini OPTION (RECOMPILE) berguna.
LOGIKnya Logika, kueri Anda tidak lagi efisien, tidak masalah untuk sejumlah kecil baris, tetapi tidak lagi skala. Ini biasanya melibatkan analisis mendalam dari Rencana Kueri. Misalnya, Anda tidak dapat lagi melakukan hal-hal dalam jumlah besar, tetapi harus melakukan Chunk dan melakukan Commit yang lebih kecil, atau Cross Product Anda baik-baik saja untuk set yang lebih kecil tetapi sekarang membutuhkan CPU dan Memori karena skala lebih besar, ini mungkin juga berlaku untuk menggunakan DISTINCT, Anda memanggil fungsi untuk setiap baris, pencocokan kunci Anda tidak menggunakan indeks karena konversi jenis CASTING atau NULLS atau fungsi ... Terlalu banyak kemungkinan di sini.
Secara umum ketika Anda menulis kueri, Anda harus memiliki beberapa gambaran mental tentang bagaimana data tertentu didistribusikan dalam tabel Anda. Kolom misalnya, dapat memiliki jumlah nilai yang berbeda yang terdistribusi secara merata, atau dapat miring, 80% dari waktu memiliki seperangkat nilai tertentu, apakah distribusi akan sering bervariasi dari waktu ke waktu atau cukup statis. Ini akan memberi Anda ide yang lebih baik tentang cara membangun kueri yang efisien. Tetapi juga ketika debugging kinerja permintaan memiliki dasar untuk membangun hipotesis mengapa itu lambat atau tidak efisien.
sumber
Untuk menambah daftar yang sangat baik (diberikan oleh @CodeCowboyOrg) dari situasi di mana OPTION (RECOMPILE) dapat sangat membantu,
sumber
Tindakan pertama sebelum menyetel kueri adalah defrag / membangun kembali indeks dan statistik, selain itu Anda membuang-buang waktu.
Anda harus memeriksa rencana pelaksanaan untuk melihat apakah itu stabil (sama ketika Anda mengubah parameter), jika tidak, Anda mungkin harus membuat indeks penutup (dalam hal ini untuk setiap tabel) (mengetahui bahwa sistem Anda dapat membuat yang juga berguna untuk pertanyaan lain).
sebagai contoh: buat index idx01_datafeed_trans Pada datafeed_trans (feedid, feedDate) TERMASUK (acctNo, tradeDate)
jika paket itu stabil atau Anda bisa menstabilkannya, Anda bisa mengeksekusi kalimat dengan sp_executesql ('sql kalimat') untuk menyimpan dan menggunakan rencana eksekusi yang sudah diperbaiki.
jika paket tidak stabil Anda harus menggunakan pernyataan ad-hoc atau EXEC ('sql kalimat') untuk mengevaluasi dan membuat rencana eksekusi setiap kali. (atau prosedur tersimpan "dengan kompilasi ulang").
Semoga ini bisa membantu.
sumber
Necroing pertanyaan ini tetapi ada penjelasan yang tampaknya tidak ada yang mempertimbangkan.
STATISTIK - Statistik tidak tersedia atau menyesatkan
Jika semua hal berikut ini benar:
Kemudian sql server mungkin salah berasumsi bahwa kolom tidak berkorelasi, yang mengarah ke perkiraan kardinalitas yang lebih rendah dari yang diharapkan untuk menerapkan kedua pembatasan dan rencana eksekusi yang buruk dipilih. Perbaikan dalam hal ini adalah membuat objek statistik yang menghubungkan dua kolom, yang bukan operasi yang mahal.
sumber