Sayfalar

25 Ağustos 2012 Cumartesi

Bulk Insert Yöntemi

Büyük veriler ile çalışan yazılımcılar çok fazla kaydı bir tabloya yazarken ederken klasik yöntemler ile kod yazıldığında çok uzun süren döngülere girildiğini az çok bilirler. Örneğin bir döngü ile tabloya 1000 kayıt 1 saniyede yazılırken 10000 kaydın lineer bir artış ile 10 saniyede yazılması beklense de eksponansiyel olarak artarak bu 40 saniyeye kadar çıkabilir. Bu da ciddi performans sorunlarına neden olabilir.

İşte bunun gibi performans sorunlarını çözmek için veri tabanları üzerinde bir tabloya toplu olarak veri yazmaya yarayan ve birçok kişinin bilmediği Bulk Insert yöntemi vardır. Her veri tabanı sisteminin kendine has bir Bulk Insert yöntemi vardır. Bu yöntemi anlatmak için makalede MS SQL Server üzerindeki çalışma şeklinden bahsedeceğim.

SQL Server üzerindeki Bulk Insert yönteminin çalışma prensibi, SQL Server’ın metin tabanlı veri kaynağındaki (metin dosyası) belli bir karakter ile alanları birbirinden ayrılmış veri listesini kendi kendine okuyarak insert etmesine dayanmaktadır. SQL Server’a bu işlemi yaptırmak için BULK INSERT SQL komutu çalıştırılmaktadır.

Nasıl çalıştığını daha iyi anlayabilmek için basit bir örnek yapalım. Aşağıdaki yapısı görülen TARGET_TABLE adında bir tablomuz olduğunu varsayalım.

Bu tabloya topluca atılmak istenen 10 adet kayıt için gereken veriler Unicode encoding ile hazırlanmış C:\SOURCE.DAT dosyasında belli bir formatta sağlanmış olsun. Dosyanın içeriği aşağıdaki gibi olsun:

f303c9aa-ef48-4994-91c0-d6530c18dbd7|5|adres 0|2012-02-10 10:56:58|0
1c0e3668-33d3-4fcc-9aa7-65e6c6fcc468|5|adres 1|2012-02-10 10:56:58|0
1d7c6399-217f-4585-9dd4-aec9d290d5cb|5|adres 2|2012-02-10 10:56:58|0
fc5e811c-631a-4124-9ef8-20b441d2d660|5|adres 3|2012-02-10 10:56:58|1
ce3adbca-5dac-459b-91d1-8d32e226cabc|5|adres 4|2012-02-10 10:56:58|0
e2b53769-2882-4bfa-a221-7c94a3ea27fc|5|adres 5|2012-02-10 10:56:58|0
d631fa0c-bb05-46a2-9b46-b1ff5104eb11|5|adres 6|2012-02-10 10:56:58|0
4ff9e35d-c8d2-4ca0-94d2-91f035cf940e|2|adres 0|2012-02-10 10:56:58|0
cbab6f78-2a1d-4217-b1d5-60a09b823cbc|2|adres 1|2012-02-10 10:56:58|1
652cb375-fbf5-46ce-96ab-5f0990ef1cb3|2|adres 2|2012-02-10 10:56:58|0


Yukarıdaki veriye baktığımızda “|” alan ayracı, “\n” (new line) da satır ayracı olmak üzere alanların sıraları ve veri tipleri 1252 kod sayfasına göre hedef tablo alanlarının sıraları ve tipleri ile eşleşmektedir. O zaman aktarımı yapmak için aşağıdaki komutu çalıştırabiliriz:

BULK INSERT TARGET_TABLE FROM 'C:\SOURCE.DAT' WITH (DATAFILETYPE ='WIDECHAR', FIELDTERMINATOR = '|', ROWTERMINATOR = '\n', CODEPAGE = '1252')
Buradaki parametreleri kısaca açıklamak gerekirse:

  • DATAFILETYPE =’WIDECHAR’ : Dosya Unicode olarak yazıldı
  • FIELDTERMINATOR = ‘|’ : Tablodaki bir satırın alanları metin üzerinde “|” karakteri ile ayrılmış
  • ROWTERMINATOR = ‘\n’ : Tablodaki her satır, dosyadaki LF (Line Feed/Satır Sonu) karakteri ile ayrılmış. *
  • CODEPAGE = ’1252′ : Dosyayı 1252 kod sayfasında oku

* Line Feed karakterinin farklı platformlardaki detaylı bir incelemesine WikiPedia üzerindeki New Line makalesinden ulaşabilirsiniz.

Bu işlem sadece basit ve statik bir örnektir. Daha geliştirmek istersek bunu bir Stored Procedure (SP) içinde yazmak ve parametrik çalışmasını sağlayabiliriz. Uygulamamızın ürettiği 100000 adet veri nesnesini tek tek INSERT INTO çalıştırarak tabloya yazmak yerine bunları dönerek bir metin dosyası üretip bir yere kaydedebilir, bu dosyanın yolunu hazırladığınız SP’e parametre şeklinde vererek çalıştırabilirsiniz. Ancak böyle yapıyorsanız uygulamanın da bu yola erişimi olmalıdır. Eğer uygulama ve veri tabanı sunucusu ayrı makinelerde ise bu yol network paylaşımı olabilir; Yeter ki dosyanın fiziksel konumu SQL sunucusu üzerinde olsun.

Bulk Insert yöntemini kullanırken dikkat edilmesi gereken hususlardan biri kaynak dosyanın SQL Server tarafından ulaşılabilen ve okuma izni olan bir dosya olması gerekmesidir. Gerekli izni kontrol etmek için SQL Server servisinin oturum açan kullanıcısını bulup ona yetki verilip verilmediğine bakabilirsiniz.

Bir ikinci trick olarak SP içinde kullanımından bahsedebiliriz. Üstte yazdığımız örnekteki komutu direkt olarak bir SP içine yazabilirsiniz ancak bu düz bir metindir.

BULK INSERT TARGET_TABLE FROM @source WITH (DATAFILETYPE ='WIDECHAR', FIELDTERMINATOR = '|', ROWTERMINATOR = '\n', CODEPAGE = '1252')

Şeklinde bir işlem yapmaya çalıştığınızda SP’niz derlenmeyecektir. Bunun önüne geçmek için aşağıdaki gibi bir yazıma ihtiyacınız vardır.

EXEC ('BULK INSERT TARGET_TABLE FROM ''' + @source  + ''' WITH (DATAFILETYPE =''WIDECHAR'', FIELDTERMINATOR = ''|'', ROWTERMINATOR = ''\n'', CODEPAGE = ''1252'')')

Buradan anlaşılacağı gibi hedef tabloyu da parametrik olarak verebilirsiniz, böylece generic bir BULK INSERT saklı yordamınız olacaktır.

Son bir dipnot olarak bu işlemin senkron çalıştığını ve TransactionContext’ine alındığını (yani Commit/Rollback yapılabileceğini) söyleyebiliriz.

BULK INSERT SQL komutu ile ilgili geniş bilgiye MSDN üzerinden ulaşılabilir. Herkese kolay gelsin.

Hiç yorum yok:

Yorum Gönder