Makale Özeti

Yazılım geliştiricilerin dünyasında, verinin bir yerden başka bir yere aktarılması sıklıkla yapılan bir çalışmadır. Bu makalemizde de, .NET 2.0 ile gelen SqlBulkCopy sınıfını kullanarak; farklı veri kaynaklarından SQL Server veritabanına nasıl veri kopyalanabileceğini göreceğiz.

Makale

SqlBulkCopy Sınıfını Kullanarak Veri Transferi

Çalıştığım merkezdeki 6 yıllık milyonlarca verinin bir yerden başka bir yere aktarılması gerekiyordu. Bu sefer alışmış olduğum klasik yöntemler yerine başka bir çözüm aradım. Sonunda.NET 2.0 ile gelen SqlBulkCopy sınıfı ile karşılaştım. İşte bu makalede bu sınıf ile neler yapabileceğimize bir göz atacağız.

Bir kaynaktan başka bir kaynağa veri transferi, yazılım dünyası içinde sıklıkla karşılaşılan bir durumdur. Bu işlem birçok farklı senaryo için uygulanabilir. Eski sistemden yeni sisteme geçiş, veri yedekleme, farklı yerlerden veri toplama vs. .NET 2.0, farklı kaynaklardan SQL Server veritabanına veri aktarmanıza olanak veren SqlBulkCopy sınıfını içerir (System.Data.SqlClient.SqlBulkCopy). İşte bu makalede, SqlBulkCopy sınıfını farklı yönleriyle ele alacağız.

Veritabanı Tasarımı

Şimdi, herkesin de rahatlıkla uygulayabilmesi için elimizdeki kaynakları da kullanarak bir veritabanı tasarımı yapalım. SQL Server 2005 kurulu tüm bilgisayarlarda bulunan AdventureWorks veritabanındaki Person.Address tablosunu baz alarak 3 yeni tablo yapalım. Aşağıdaki veritabanı diyagramını inceleyerek; tabloları oluşturabilirsiniz. Çok sade, hoş bir tasarım oldu :)

Burada Address_Old ve Address_New tablolarımız aynı eski Address tablosunda olduğu gibi aynı şemaya sahip. Sadece Address_Specific tablosu bunlardan farklılık gösteriyor. Bunun sebebini makalenin ilerleyen bölümlerinde bulabileceksiniz.

Aslında etkili gösterim için daha fazla kayıt içeren bir tablo bulmak isterdim ama Address_Old tablosu da yeterli olacak sanırım. Bu tablo tam 19614 satır içeriyor. Şimdi burada asıl düşünülmesi gereken kayıtların çokluğu değil; ani ya da acil bir durum karşısında bu kadar kaydı nasıl bir yerden başka bir yere aktaracağımızdır. Örneğin, tüm bu tablo satırlarını Address_Old tablosundan Address_New tablosuna nasıl aktaracağız. Şimdi bu gibi senaryolara bir bakalım.

Address_Old Tablosundan Address_New Tablosuna Veri Transferi

SqlBulkCopy, WriteToServer adında veriyi bir kaynaktan hedefteki kaynağa transfer etmek için kullanılan bir instance metot içerir. WriteToServer metodu, DataRow[] dizisinde, DataTable da ve DataReader üzerinde işlem yapabilir. Duruma göre istediğiniz herhangi bir taşıyıcıyı seçebilirsiniz. Bunda bir kısıtlama yok ama birçok durumda olduğu gibi DataReader ı seçmek iyi olur sanırım. Bunun nedeni DataReader yapısından kaynaklanır. DataReader sadece ileri (forward-only) ve salt okunabilir (read-only) çalışır. Herhangi bir şekilde veri tutmasına, bağlamasına gerek yoktur ve işte bu yüzden DataTable ve DataRows[] dan kat kat hızlı çalışır (bu senaryoda). Aşağıdaki kodda kaynak tablomuzdan hedefteki tablomuza veriyi nasıl aktarabileceğimizi görebilirsiniz.

Şimdi burada bahsedilecek birkaç nokta var. Öncelikle, veritabanı tablosundan satırları çekmek için DataReader kullanıyoruz. SqlBulkCopy sınıfı nesnesi bulkCopy, DestinationTableName özelliğine burada Address_New olan tablomuzu set ediyor. Address_New burada hedef tablomuz. Çünkü verileri Address_Old tablosundan, Address_New tablosuna aktaracağız. bulkCopy nesnesi, NotifyAfter özelliği tarafından belirlenen satırlara ulaştıktan sonra SqlRowsCopied olayını da çalıştırıyor. Bunun anlamı da, bu olay NotifyAfter özelliği 1000 olarak ayarlandığından dolayı; her 1000 satırdan sonra SqlRowsCopied olayı çalıştırılacaktır.

Burada BatchSize özelliği de, performans büyük çoğunlukla ona bağlı olduğu için oldukça önemlidir. BatchSize, veri transferini başlatmak için bir defada veritabanına ne kadar satırın gönderilmesi gerektiğini tutar. Burada bu değeri biz 500 olarak ayarladık. Bunun anlamı bir defada, DataReader, bulk copy işlemini gerçekleştirebilmek için veritabanına gönderilmek üzere 500 satır okuyacaktır. Varsayılan olarak BatchSize 1 olarak ayarlanmıştır. Bu da, veritabanına her bir satırın tek tek gönderileceği anlamını taşır.

Farklı BatchSize değerleri size farklı sonuçlar verecektir. Burada hangi BatchSize değerinin size en çok uyacağını farklı testler yaparak bulabilirsiniz.

Farklı Şemalara Sahip Tablolar Arasında Veri Transferi

Bir önceki örnekte, her iki tablomuzda aynı şemaya sahipti. Fakat bazen, farklı şemalara sahip tablolar arasında da veri transferi yapmak zorunda kalabiliyoruz. Şimdi bir adres tablosu içindeki tüm adres satırlarını ve posta kodlarını, Address_Old tablosu içinden Address_Specific tablosu içine aktarmak istediğimizi varsayalım. Farklı sütun isimlerini sahip oldukları için, dolayısıyla bu iki tablonun şemaları da farklıdır. En başta gördüğümüz veritabanı tasarımını gösteren diyagram resminde de bunu görebiliriz.

Burada ColumnMappings koleksiyonu, kaynak tablo ile hedef tablo arasındaki sütunları belirlemede kullanılır.

XML Dosyasından Veritabanı Tablosuna Veri Transferi

Veri kaynaklarını sadece veritabanı tabloları ile sınırlayabilir miyiz? Elbette hayır. XML dosyalarını da veri kaynağı olarak kullanabiliriz. Aşağıda, bulk copy işleminde kaynak olarak kullanabileceğimiz; çok basit bir XML dosyası var.

Addresses.XML Dosyası

Bu da kaynak kodumuz.

Dosya ilk olarak DataTable içinde okunuyor ve daha sonra SqlBulkCopy sınıfının WriteToServer metoduna aktarılıyor. Yine, hedef tablo olarak, Address_Specific tablosunu seçtiğimiz için ColumnMappings kullanarak sütünları belirliyoruz.

Daha bunun gibi birçok senaryo yaratarak sizde değişik örnekler yapabilirsiniz. Bu arada SqlBulkCopy sınıfının gücünü özellikle belirtmek isterim. Örneğimizde kullandığımız 19614 satırlık kaydın bir tablodan diğerine aktarılması, bir göz kırpması için geçen süre ne kadarsa o kadar sürdü :)

Özet

Bu makalede, .NET 2.0 ile birlikte gelen SqlBulkCopy sınıfını nasıl kullanabileceğimizi gördük. SqlBulkCopy sınıfı, bir veri kaynağından SQL Server veritabanına veri transfer etmek istediğimizde; işimizi oldukça kolaylaştırır. Sizde değişik senaryolarla bunu test edebilirsiniz.

Not: Bu sınıf, .NET Framework .NET Compact Framework 3.0 ve 2.0 versiyonlarının tümünde desteklenmektedir.

Bir sonraki makalelerde görüşmek üzere. İyi çalışmalar...


Tayfun AKCAY

tayfun@tayfunakcay.com