Fırat Esmer

Microsoft Yazılımları

ADO.NET Bağlantı Havuzu

Herhangi bir veritabanı ile ilgili bir işlem için açılan bağlantı, sunucu tarafında oturum açılmasına sebep olur. Açılan her bağlantı yeni bir istek, her istek yük anlamına gelir. Birazdan okuyacağınız makalede tüm isteklerin bir bağlantıdan gönderilmesi (connection pooling - bağlantı havuzu) ile her isteğin ayrı ayrı bağlantılar üzerinden gönderilmesi arasındaki farkı ve avantajları göreceksiniz.

Senaryo : Veritabanına, içerisinde pooling özelliği true ve false olan 2 farklı bağlantı açacağım. Bize ne kadarlık süreye mal olacağını ve SQL Server Profiler'da nasıl görüneceğini göstereceğim.

Bilinmesi Gerekenler :

  • Makaledeki örnek .NET Framework 4.0 (Windows Form) ve Visual Studio 2010 ile hazırlandı,
  • Makalede Northwind veritabanı üzerinden bağlantı açacağım. Eğer Northwind veritabanına sahip değilseniz hata verecektir. İndirmek için buraya tıklayın. Northwind veritabanı kullanmamın sebebi çoğu yazılımcının mevcut olması. Projenin boyutunu büyütmemek adına veritabanını projeme eklemedim.

Neler Öğreneceksiniz :

  • Tanımlanan bağlantı üzerindeki pooling (havuz) mantığını kavrayacaksınız,
  • Min Pool Size ve Max Pool Size kavramlarını öğreneceksiniz.

Önceklikle şunu belirtmeliyim ki eğer tanımladığınız bağlantı cümlesine "pooling" özelliğini eklemezseniz, varsayılan olarak true olacaktır. Yani oluşturulmuş bağlantı havuzu üzerinden işlemlerinizi gerçekleştirecekseniz bir şey yapmanıza gerek yok. Ancak her istek için ayrı bir bağlantı tanımlamak istiyorsanız aşağıdaki gibi bağlantı tanımlayabilirsiniz.

SqlConnection connection = new SqlConnection("server=.; database=northwind; integrated security=sspi; pooling=false");

İlk olarak veritabanı ile bağlan kuralım ve SQL Server Profiler'dan veritabanında neler olduğuna bakalım.

// 1 numaralı bağlantım.
using (SqlConnection connection = new SqlConnection("server=.; database=northwind; integrated security=sspi;"))
{
  connection.Open();
}

// 2 numaralı bağlantım.
using (SqlConnection connection = new SqlConnection("server=.; database=ReportServer; integrated security=sspi;"))
{
  connection.Open();
}

// 1 numaralı bağlantım ile aynı olduğu için 3. bağlantıyı açmayıp, 1 numaralı bağlantı üzerinden işlemi gerçekleştirecek.
using (SqlConnection connection = new SqlConnection("server=.; database=northwind; integrated security=sspi;"))
{
  connection.Open();
}

Ve sonuç aşağıdaki gibi olacaktır. 

SQL Server Profiler

Gördüğünüz gibi tek bir havuzdan yönetilen bağlantılar sonucu, aynı bağlantılari çin tekrar tekrar oturum açılmadı. Gelin şimdi her istek için ayrı bir bağlantı açalım ve bu işlemin ne kadar süreceğine bakalım.

SqlConnection connection;

DateTime start = DateTime.Now;

// 1000 kere bağlantıyı açıp kapatacağız.
for (int i = 0; i < 1000; i++)
{
  connection = new SqlConnection("server=.; database=northwind; integrated security=sspi; pooling=false");

  connection.Open();
  connection.Close();
  connection.Dispose();
}

DateTime end = DateTime.Now;

// Geçen zamanın sonucunu alacağız.
TimeSpan result = end - start;

MessageBox.Show(String.Format("Açılan bağlantıların işlem süresi : {0}", result.ToString()));

Yukarıdaki işlemin sonucu tam olarak 00:00:07.3951136 saniye sürdü. Anlattığım kadarıyla "pooling=false" dediğimiz için bin ayrı oturum açılmış olması lazım. 

SQL Server Profiler

Evet liste böylece akıp gidiyor aşağıya doğru. Şimdi... Şimdi "pooling=true" yapacağız. Yani tek bir bağlantıyı açık tutacağız ve işlemleri bellekteki bağlantıdan yürüteceğiz. Gelin bunun ne kadar zaman alacağına ve SQL Server Profiler'da nasıl gözükeceğine bakalım.

SqlConnection connection;

DateTime start = DateTime.Now;

for (int i = 0; i < 1000; i++)
{
  connection = new SqlConnection("server=.; database=northwind; integrated security=sspi; pooling=true");

  connection.Open();
  connection.Close();
  connection.Dispose();
}

DateTime end = DateTime.Now;

TimeSpan result = end - start;

MessageBox.Show(String.Format("Açılan bağlantıların işlem süresi : {0}", result.ToString()));

Yukarıdaki işlemin sonucu tam olarak 00:00:00.2275035 saniye sürdü. Buradaki asıl mantık şu; açılan ilk bağlantı bellekte tutulur ve geri kalan bağlantılar için kullanılır. Gelin bir de SQL Server Profiler'da nasıl göründüğüne bakalım.

SQL Server Profiler

Dediğim gibi, tek bir bağlantı açıldı ve geri kalan bağlantılar bellekten kullanıldı. Gördüğünüz gibi inanılmaz performans artışı sağlandı. Peki bağlantı havuzundaki bağlantı sayımıza sınır koyma şansımız var mı? Evet.

Max Pool Size : Bağlantı havuzumuzdaki saklanacak en fazla bağlantı sayısını belirtir. Varsayılan olarak 100'dür.

Min Pool Size : Bağlantı havuzumuzdaki saklanacak en az bağlantı sayısını belirtir. Varsayılan olarak 0'dır.

Eğer Max Pool Size'ı 50 olarak belirtir ve 50'den fazla bağlantı açarsanız (kapatmadan), şöyle bir hata ile karşılacaksınız.

Hata

"Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached." Diyor ki : Zaman aşımı süresi doldu. Havuza bağlantı elde edilemeden zaman aşımı süresi doldu. Bu, tüm havuz bağlantıları kullanıldığı ve en büyük havuz boyutuna erişildiği için oluşmuş olabilir. Bağlantınızı kapatmayı asla unutmayın! (Bağlantılı sınıflarda tabii)

Son olarak SqlConnection üzerinden kullanabileceğiniz 2 adet statik metottan bahsetmek istiyorum.

  1. SqlConnection.ClearAllPools() ile tüm havuzları temizleyebilir,
  2. SqlConnection.ClearPool(SqlConnection) ile belirli bağlantı havuzunu temizleyebilirsiniz.

Makaledeki örnek uygulamayı indirmek isterseniz buraya tıklayın.

Yorumlar (2) -

  • Mehmet Akif Vurucu

    4.12.2016 13:51:07 | Yanıtla

    Hocam yazınız çok faydalı öncelikle teşekkür ederim. Ancak bir sorum olacak. Max pool size değerini 10000000 gibi yüksek vermenin bir sakıncası var mı veya ideali kaçtır.

    • Fırat Esmer

      4.12.2016 14:18:55 | Yanıtla

      Merhaba,
      Teşekkür ederim Mehmet.

      Max Pool Size'ı yüksek vermenin "sakıncası" olarak görülebilecek şeylerin başında, uygulamanın veri tabanına gereğinden fazla bağlantı açabileceği yeneteğini kazandırmaktır. Yani, belli bir limit kuralınız yoksa pek de ciddi bir kaygı taşımayı gerektirecek bir şey değil.

      Gelelim ideal bağlantı sayısına, böyle bir şey yok. Bu tamamen size, ve uygulamanıza bağlı bir durum. MS SQL Server Database Engine instance'ında ne kadar bağlantı açıldığı, ne gibi işlerin yapıldığı bilgisine ulaşmak istiyorsanız "sp_who" stored procedure'unu kullanarak ihtiyaçlarınızı belirleyebilirsiniz.

      Daha fazla bilgi için => msdn.microsoft.com/en-us/library/ms174313.aspx

Yorum ekle

Loading