SqlDataReader neden aktif bir SqlConnection nesnesine ihtiyaç duyar?
Bir süredir SiteBuilders mail grubunu çok dikkatli bir biçimde takip edemiyorum. Birkaç gün önce son ~1200 mesajın başlıklarına göz atma fırsatı buldum. Güzel de bir konu yakaladım. SqlDataReader neden aktif bir SqlConnection nesnesine ihtiyaç duyar?
Sayın Murat Atalay’ın cevabını bulmak istediği bir konu. Açıkçası konu ile ilgili kesinleşmiş bilgilerim yok. Sadece şimdiye kadar bilgisi olan kişilerden aldığım bilgiler, bulduğum birkaç makalede okuduğum bilgiler ve bazı tecrübelerim aşağıdaki gibi bir cevap yazmama sebep oldu.
Selam,
Baglanti acik tutulmak zorunda cunku ayni anda birden fazla baglanti uzerinden birden fazla DataReader islem yapiyor olabilir ve sizing baglantinizin her seferinde kesilip tekrar baglanmasi durumunda hangi “stream”den yeni satiri alacaginiz bilinemez.
Ayrica asagidaki yazismalardan birisinde DataReader’in donen kume setini kendi belleginde tuttugu gibi hatali bir bilgi var. Zira DataReader’in en onemli ozelligi bilgiye ihtiyac duydugunda istekte bulunmasi ve DataTable gibi memory’yi somurmuyor olmasidir. Kume setiniz SQL server memory’si uzerinde tutulur. Uzunca bir sure islem yapmazsaniz ve bu arada SQL server kume setini memory azalmasi gibi bir sebeple temizlemek zorunda kalirsa, sorgunuz tekrar calistirilir ve kalinan index uzerinden bilgiler sunulmaya devam eder. Bu durumda SQL profiler uzerinde sorgunun tekrar calistigini da gorursunuz. Ancak cok kullanilmayan bir sistemde bununla karsilasmaniz olagan degil.
Benim elimde olan teknik bilgi bu sekilde ayrica tecrubelerim de bu yonde. Elinde baska bilgisi olan birileri varsa ve benim de yanlis bildigim yerler varsa, dogrularini ogrenmeye acigim cunku DataReader’in calisma prensibi uzerine cok kapsamli bir makale henuz yayinlanmis degil veya ben gormedim.
Murat Bey’den şu şekilde bir cevap geldi, ki gayet mantıklı bir cevap.
Coşkun bey,
yanıtınız için teşekkür ederim. Doğrusunu isterseniz yazdığınız cümlede hala SQL ile bağlantının neden açık olması gerektiğini net olarak anlayamadım.Bayağı araştırdım sanırım bu konuyu anlayamacağım.
Diğer sorun şu, sorgu sonucunun SQL Server memory’sinde tutulduğunu söylüyorsunuz. Bundan gerçekten emin miyiz. Uzaktaki SQL Server’dan veri sroguladım ve Command nesnesini execute ettikten sonra makinemin network kabolsunu çektim daha sonra reader’i döngüye sokup verileri okumaya başladım. Verileri rahatlıkla listelemiş oldum. Bu durum, verilerin yerel memory’de bulunduğunu göstermez mi.
while (Reader.Read())
{
Console.WriteLine(Reader["MusteriAdi"]);
Console.ReadLine();//Burada bir sonraki kayda geçmesi için ENTER'e basıyoruz.
//İlk kaydı ekrana bastırdıktan sonra network kablosunu çıkardım
}
Ve kendisine şu şekilde bir cevap verdim.
Selam,
~100.000 kayitlik bir tabloda ayni islemi ilk kaydi okuduktan hemen sonra tekrar deneyebilir misiniz? Verileri block’lar halinde aliyor diye tahmin ediyorum. Sonucta her bir satir icin tekrar network baglantisi acmak da performansa aykiri bir durum.
Eger yine bahsettiginiz sonucu alirsaniz, Microsoft’daki product group’la direkt olarak iletisime gececegim.
Murat Bey’in vereceği cevabı merakla bekliyorum. Eğer Murat Bey haklıysa, sonrasında ilgili ürün grubundan alacağım cevabı da sizinle paylaşacağım.
SqlDataReader, sunucunun belleğine çıkan sonuç kümesini paketler haline istemciye alır. Bu paketlerin bir tanesinin içerisinde, tablonun yapısına bağlı olarak, birçok satır yer alabilir.
Bahsi geçen paketlerin boyutları, Sql Server’a açılan bağlantıya ait bağlantı cümlesinde “packet size” anahtarıyla bildirilebilir. Varsayılan değeri 8000byte olan bu anahtara, 512 ile 32768 arasında herhangi bir değer verilebilir. Böylece SqlDataReader’ın çalışma yapısı, ihtiyaçlara göre şekillendirilerek bir takım optimizasyonlar yapılabilir. Örneğin,resim ve uzun metinler gibi büyük nesnelerin sunucundan okunması durumunda, ufak paket boyutu network trafiğini gereksiz yere arttıracaktır. Bu durumda paket boyutunu yükseltmek gerekir.
Saygılar
Cenk Bey,
Paylaştığınız bilgiler için teşekkür ederim. Oldukça değerli bilgiler olduğunu itiraf etmeliyim.
Teşekkürler,
Coşkun
Merhabalar,
Yukarıdaki durumu test ettik. command nesnesi ile ExecuteReader’ı çalıştırıp SqlDataReader’a aktardık. Daha sonra ağ bağlantısını kesip While ile döndüğümüz de 25 kayıtlı tablodan 19 adet kaydı ekrana basıp 20. kayıtta hataya düştü.
SqlConnection con = new SqlConnection(“Database=Database;Server=10.0.0.24; Uid=sa;pwd=111”);
SqlCommand cmd=new SqlCommand(“select * from Invoice”,con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
Console.ReadKey();//burada ağ bağlantısını kesip devam ettiriyoruz.
while (dr.Read())
{
Console.WriteLine(dr[“InvoiceID”]);
}
Console.ReadKey();