Bir SQL grubunu hazırlanan SQL grubunu yürütmekten ayrı olarak hazırlamak etkili bir yapıdır **SQL Server için yürütme planlarının nasıl önbelleğe alındığı dikkate alınmaz. Hazırlık (ayrıştırma, herhangi bir parametreyi bağlama ve derleme) ve yürütme adımlarının ayrılması, yalnızca önbellek olmadığında mantıklıdır. Amaç, mevcut bir planı yeniden kullanarak ayrıştırma ve derleme için harcanan zamandan tasarruf etmektir ve dahili plan önbelleğinin yaptığı da budur. Ancak tüm RDBMS'ler bu önbellekleme düzeyini yapmaz (bu işlevlerin varlığından açıkça anlaşılır) ve bu nedenle bir planın "önbelleğe alınmasını" istemek ve bu önbellek kimliğini kaydetmek ve daha sonra yeniden kullanmak istemciye bırakılır. o. Bu, istemci kodu (ve bunu yapmayı ve doğru yapmayı hatırlamak için programcı) üzerinde ek bir yüktür. Aslında, IDbCommand.Prepare () yönteminin MSDN sayfasında şunlar belirtilir:
Sunucu yeniden kullanım planlarını otomatik olarak önbelleğe alır; bu nedenle, bu yöntemi doğrudan istemci uygulamanızda çağırmanıza gerek yoktur.
Kadarıyla benim test gösterdiği gibi çağırarak, (sen Soru gösterileceğini eşleşir), unutulmamalıdır SqlCommand.Prepare () yok, değil yapmak bir -sadece operasyonu "hazırlamak": Bu çağırır sp_prepexec hazırlar hangi ve SQL yürütür ; o aramazsa sp_prepare ayrıştırma ve sadece derlemek (ve herhangi bir parametre değerlerinin, sadece isimleri ve veri türleri içinde almaz). Bu nedenle, SqlCommand.Prepare
derhal yürütme yaptığı için (hedefin yürütmeyi ertelemek olduğunu varsayarak) çağrılmanın herhangi bir "derleme öncesi" yararı olamaz . ANCAK , bunun yerine SqlCommand.Prepare()
arama sp_prepexec
yapsa bile , arama yapmanın ilginç bir potansiyel küçük yararı vardır sp_prepare
. Lütfen nota bakın (** ) ayrıntılar için altta.
Hatta benim test gösterileri SqlCommand.Prepare()
denilen (ve bu çağrı lütfen unutmayın edilir değil , SQL Server üzerinde herhangi komutları), ExecuteNonQuery
ya da ExecuteReader
o tamamen yürütülür izler ve ExecuteReader ise, bu satırları döndürür. Yine de, SQL Server Profiler, SqlCommand.Execute______()
çağrıdan sonraki ilk çağrının SqlCommand.Prepare()
"SQL Hazırla" olayı .Execute___()
olarak kaydedildiğini ve sonraki çağrıların "Exec Prepared SQL" olayları olarak kaydedildiğini gösterir.
Test Kodu
PasteBin'e şu adresten yüklendi: http://pastebin.com/Yc2Tfvup . Kod, bir SQL Server Profiler izleme çalışırken (veya bir Genişletilmiş Olaylar oturumu) çalıştırılması amaçlanan bir .NET / C # Konsol Uygulaması oluşturur. Her adımdan sonra duraklar, böylece hangi ifadelerin belirli bir etkisi olduğu açıktır.
GÜNCELLEME
Daha fazla bilgi ve aramaktan kaçınmak için olası bir neden bulundu SqlCommand.Prepare()
. Testlerimde fark ettiğim bir şey var ve bu test Konsolu Uygulamasını çalıştıran herkes için nelere dikkat edilmelidir: asla açık bir çağrı yapılmaz sp_unprepare
. Biraz kazma yaptım ve MSDN forumlarında aşağıdaki yayını buldum:
SqlCommand - Hazırla ya da hazırlamıyor musun?
Kabul edilen cevap bir sürü bilgi içerir, ancak dikkat çekici noktalar şunlardır:
- ** Hazırlanan şey sizi gerçekten kurtarır, öncelikle sorgu dizesini tel üzerinden iletmek için gereken süredir.
- Hazırlanan bir sorgu, önbelleğe alınmış bir planın kaydedileceğini garanti etmez ve sunucuya ulaştığında geçici bir sorgudan daha hızlı değildir.
- RPC'ler (CommandType.StoredProcedure) hazırlanırken hiçbir şey kazanmaz.
- Sunucuda, hazırlanmış bir tanıtıcı temelde yürütülecek TSQL içeren bir bellek içi haritaya bir indekstir.
- Harita her bağlantı için ayrı ayrı saklanır, çapraz bağlantı kullanımı mümkün değildir.
- İstemci bağlantıyı havuzdan yeniden kullandığında gönderilen sıfırlama haritayı temizler.
SQLCAT ekibinden ilgili olduğu görülen ancak ODBC'ye özgü bir sorun olabileceği halde SqlClient, SqlConnection öğesinin atılmasıyla doğru şekilde temizlendiğinde de aşağıdaki gönderiyi buldum. SQLCAT direği, bunun bağlantı havuzunun temizlenmesi vb.
Hazırlanan SQL ifadelerine dikkat edin
SONUÇ
Verilen:
- aramanın tek gerçek yararı
SqlCommand.Prepare()
, sorgu metnini tekrar ağ üzerinden göndermenize gerek olmadığıdır.
- sorgu metnini çağırma
sp_prepare
ve sp_prepexec
bağlantının belleğinin bir parçası olarak kaydetme (örn. SQL Server belleği)
Tek potansiyel fayda olumsuz daha fazla sunucu belleği alıyor iken ağ paketleri kaydetme çünkü çağrı karşı tavsiye ederim SqlCommand.Prepare()
. Çoğu durumda tüketilen bellek miktarı muhtemelen çok az olsa da, çoğu DB sunucusu en az 10 Megabit (bu günlerde 100 Megabit veya Gigabit) bağlantısı üzerinden doğrudan uygulama sunucularına bağlandığından ağ bant genişliği nadiren bir sorundur ( hatta bazıları aynı kutuda ;-). Bu ve bellek neredeyse her zaman ağ bant genişliğinden daha az kaynaktır.
Sanırım, birden çok veritabanına bağlanabilen yazılım yazan herkes için standart bir arayüzün rahatlığı bu maliyet / fayda analizini değiştirebilir. Ama bu durumda bile, bunu (örneğin değil dolayısıyla ve aralarındaki farklar, farklı sağlayıcılar sağlayan "standart" DB arabirimi soyut a kolay hala yeterince olduğuna inanmak zorunda ihtiyacı çağrısına Prepare()
temel Nesne Bunu yaparken göz önüne alındığında) 'dir Uygulama kodunuzda muhtemelen yapmış olduğunuz yönlendirilmiş programlama ;-).