Bulk Data Insert / Update: Milyonlarca Veriyi En Hızlı Şekilde DB'ye Yazma
Uygulamanız büyüdükçe, yüzbinlerce hatta milyonlarca satırı veritabanına eklemeniz veya güncellemeniz gerekebilir. Tek tek INSERT veya UPDATE komutları göndermek, hem ağ trafiğini şişirir hem de veritabanı sunucusunda gereksiz yük oluşturur. Bu tür büyük veri işlemleri için özel olarak tasarlanmış yöntemler kullanmak, performansı kat kat artırabilir. Bu yazıda, .NET ekosisteminde en çok kullanılan 4 toplu veri yazma yöntemini (SqlBulkCopy, EF Core Bulk Extensions, Table-Valued Parameters ve Batch INSERT) karşılaştıracak, hangi senaryoda hangisinin tercih edilmesi gerektiğini ele alacağız.
1. Karşılaştırma Tablosu: Hangi Yöntem Ne Zaman?
| Yöntem | Performans | Esneklik | Kullanım Kolaylığı | Veritabanı Bağımlılığı | Update Desteği |
|---|---|---|---|---|---|
| SqlBulkCopy | 🟢 Çok Yüksek | 🟡 Orta | 🟡 Orta | 🔴 Yüksek (SQL Server) | ❌ Hayır (Sadece Insert) |
| EF Core Bulk Extensions | 🟢 Yüksek | 🟢 Yüksek | 🟢 Yüksek | 🟡 Orta (Çoklu DB) | ✅ Evet |
| Table-Valued Parameters (TVP) | 🟢 Yüksek | 🟢 Yüksek | 🔴 Zor | 🔴 Yüksek (SQL Server) | ❌ Hayır (Sadece Insert) |
| Batch INSERT (Multiple Rows) | 🟡 Orta | 🟢 Yüksek | 🟢 Çok Kolay | 🟢 Düşük | ✅ Evet (MERGE ile) |
2. Yöntem 1: SqlBulkCopy (SQL Server Native)
SqlBulkCopy, SQL Server'a yüksek hızlı toplu veri kopyalama (bulk copy) işlemi yapmak için kullanılan, .NET Framework'ün yerleşik sınıfıdır. Verileri doğrudan veritabanına "tablo dökümü" (table dump) şeklinde yazar.
Nasıl Çalışır?
-
Bir
DataTableveyaIDataReaderhazırlanır. -
SqlBulkCopynesnesi oluşturulur, hedef tablo belirtilir. -
WriteToServermetodu çağrılır ve veriler toplu halde gönderilir.
csharp
using SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString); bulkCopy.DestinationTableName = "Products"; bulkCopy.BatchSize = 10000; // Her seferinde 10.000 satır gönder // DataTable veya IDataReader ile verileri hazırla DataTable table = new DataTable(); // ... tabloyu doldur ... bulkCopy.WriteToServer(table);
Artıları:
-
En Yüksek Performans: Milyonlarca satırı saniyeler içinde yazabilir.
-
Transaction Desteği:
SqlBulkCopybir transaction içinde çalıştırılabilir.
Eksileri:
-
Sadece SQL Server: SQL Server dışındaki veritabanlarında çalışmaz.
-
Update Desteği Yok: Sadece
INSERTişlemi yapar. Mevcut verileri güncellemek için geçici bir tabloya yazıpMERGEile birleştirme gibi ek işlemler gerekir. -
Veri Dönüşümü Zor: Kaynak ve hedef sütunlar arasında esnek eşleme yapmak zordur.
3. Yöntem 2: EF Core Bulk Extensions (Z.EntityFramework.Extensions / EFCore.BulkExtensions)
Entity Framework Core'un doğasında toplu işlem desteği yoktur. Ancak, popüler üçüncü parti kütüphaneler bu açığı kapatır. EFCore.BulkExtensions (ücretsiz, açık kaynak) ve Z.EntityFramework.Extensions (ticari) en bilinen iki seçenektir.
Nasıl Çalışır?
EF Core context'i üzerinden çağrılan BulkInsert, BulkUpdate, BulkInsertOrUpdate gibi extension metotlar kullanılır. Kütüphane, verileri SQL Server, PostgreSQL, MySQL gibi farklı veritabanlarına uygun toplu komutlara (ör. SQL Server için SqlBulkCopy, PostgreSQL için COPY) dönüştürür.
csharp
// EFCore.BulkExtensions (Ücretsiz) using EFCore.BulkExtensions; context.BulkInsert(products); // Toplu Insert context.BulkUpdate(products); // Toplu Update context.BulkInsertOrUpdate(products); // Insert veya Update (MERGE) // Z.EntityFramework.Extensions (Ticari, daha fazla özellik) context.BulkSaveChanges(); // Tüm değişiklikleri toplu olarak kaydet
Artıları:
-
Kullanım Kolaylığı: EF Core ile doğal entegrasyon. LINQ sorgularıyla çalışır.
-
Çoklu Veritabanı Desteği: SQL Server, PostgreSQL, MySQL, SQLite gibi birçok veritabanını destekler.
-
Update Desteği:
BulkUpdateveBulkInsertOrUpdate(MERGE) ile mevcut verileri güncelleyebilirsiniz. -
Transaction Desteği: EF Core transaction'ları ile entegre çalışır.
Eksileri:
-
Performans:
SqlBulkCopykadar hızlı değildir (özellikle Z.EntityFramework.Extensions ticari sürümü daha optimize olsa da). -
Maliyet: Z.EntityFramework.Extensions ücretlidir. EFCore.BulkExtensions ücretsizdir ancak daha az özellik sunar.
-
Veri Dönüşümü: Entity modelleri ile çalıştığı için, veri dönüşümleri otomatiktir ancak esneklik sınırlıdır.
4. Yöntem 3: Table-Valued Parameters (TVP) - Tablo Değerli Parametreler
TVP, SQL Server'a tablo şeklinde parametre göndermenizi sağlayan bir özelliktir. Bir stored procedure veya sorguya, özel bir tablo tipi (User-Defined Table Type) kullanarak birden çok satırı tek bir parametre olarak iletebilirsiniz.
Nasıl Çalışır?
-
Veritabanında bir tablo tipi (UDTT) oluşturulur.
-
Bu tablo tipini parametre olarak alan bir stored procedure yazılır.
-
.NET tarafında, bir
DataTablebu tablo tipiyle eşleşecek şekilde hazırlanır. -
SqlParameterile buDataTableparametre olarak gönderilir.
sql
-- Veritabanında tablo tipi oluştur
CREATE TYPE dbo.ProductType AS TABLE (
Id INT,
Name NVARCHAR(100),
Price DECIMAL(18,2)
);
-- Stored procedure
CREATE PROCEDURE dbo.InsertProducts
@Products dbo.ProductType READONLY
AS
BEGIN
INSERT INTO Products (Id, Name, Price)
SELECT Id, Name, Price FROM @Products;
END
csharp
// .NET tarafı
DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Price", typeof(decimal));
// ... tabloyu doldur ...
using SqlCommand cmd = new SqlCommand("dbo.InsertProducts", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@Products", SqlDbType.Structured)
{
TypeName = "dbo.ProductType",
Value = table
});
cmd.ExecuteNonQuery();
Artıları:
-
Yüksek Performans:
SqlBulkCopy'e yakın performans. -
Esneklik: Stored procedure içinde karmaşık iş mantığı (validasyon, loglama, transaction) uygulanabilir.
-
Update Desteği: Stored procedure içinde
MERGEkullanarak update de yapılabilir.
Eksileri:
-
Karmaşıklık: Stored procedure ve tablo tipi yönetimi ek iş yükü getirir.
-
Veritabanı Bağımlılığı: Sadece SQL Server'da çalışır.
-
DataTable Zorunluluğu: .NET tarafında
DataTableveyaDbDataReaderkullanmayı gerektirir (modernIEnumerableile doğrudan çalışmaz).
5. Yöntem 4: Batch INSERT (Tek Sorguda Çoklu Satır)
Bu yöntem, tek bir INSERT sorgusu içinde birden çok satırı aynı anda göndermektir. Tüm veritabanları tarafından desteklenir.
sql
INSERT INTO Products (Id, Name, Price) VALUES (1, 'Laptop', 1500), (2, 'Mouse', 25), (3, 'Keyboard', 45);
csharp
// .NET'te sorguyu oluşturma (örnek, SQL Injection riskine karşı dikkatli olun!)
var values = products.Select(p => $"({p.Id}, '{p.Name}', {p.Price})");
var sql = $"INSERT INTO Products (Id, Name, Price) VALUES {string.Join(",", values)}";
Artıları:
-
Çok Basit: Anlaşılması ve uygulaması kolaydır.
-
Evrensel: Tüm veritabanlarında çalışır.
-
Transaction Desteği: Kolayca bir transaction içine alınabilir.
Eksileri:
-
Performans Sınırı: Çok büyük veri kümelerinde sorgu boyutu (query size) artar ve veritabanı sınırlamalarına takılabilir (ör. SQL Server'da max 2100 parametre).
-
SQL Injection Riski: Dinamik sorgu oluştururken dikkatli olunmalıdır (parametreli sorgu kullanmak daha güvenlidir).
-
Update Desteği: Sadece
INSERTiçin doğaldır.UPDATEiçinMERGEveya birden çokUPDATEsorgusu gerekir.
6. Yöntem Karşılaştırması: Hızlı Seçim Rehberi
| İhtiyacınız | Önerilen Yöntem |
|---|---|
| En yüksek performans, sadece INSERT, SQL Server | SqlBulkCopy |
| EF Core ile doğal entegrasyon, INSERT+UPDATE, çoklu DB | EF Core Bulk Extensions (EFCore.BulkExtensions) |
| Karmaşık iş mantığı, stored procedure ile kontrol, SQL Server | Table-Valued Parameters (TVP) |
| Basit, orta ölçekli veri, tüm DB'lerde çalışsın | Batch INSERT (Multiple Rows) |
7. Performans İpuçları ve Dikkat Edilmesi Gerekenler
-
Transaction Yönetimi: Toplu işlemlerde, tüm veriler ya başarılı olmalı ya da hiçbiri olmamalıdır. Tüm yöntemler transaction ile kullanılabilir. Ancak, çok büyük transaction'lar log dosyalarını şişirebilir. İşlemi parçalara (batch) bölmek (ör. 10.000'er kayıt) genellikle daha iyidir.
-
Batch Size (Toplu Boyut): Çok küçük batch'ler performansı düşürür, çok büyük batch'ler bellek ve ağ sorunlarına yol açar. Genellikle 5000 - 10000 arası iyi bir başlangıç noktasıdır.
-
İndeksler ve Kısıtlamalar: Toplu işlemler sırasında indeksler güncellenir, bu da performansı yavaşlatır. Mümkünse, toplu işlem öncesi indeksleri devre dışı bırakıp (disable) sonra yeniden oluşturmak (rebuild) daha hızlı olabilir.
-
Veritabanı Log Yönetimi:
SqlBulkCopyve TVP, minimal loglama (minimal logging) yapabilir, bu da performansı artırır. Ancak, bu durum veritabanı kurtarma modeline (recovery model) bağlıdır. -
Veri Doğrulama (Validation): Toplu işlem öncesi verileri uygulama tarafında doğrulamak, veritabanına hatalı veri göndermeyi engeller. Ancak, bu doğrulama işlemi de performansı etkileyebilir.
Sonuç:
Milyonlarca veriyi veritabanına yazmak, doğru aracı seçmekle başlar. SqlBulkCopy, saf performans gerektiğinde tartışmasız liderdir. EF Core Bulk Extensions, EF Core kullanıyorsanız ve update ihtiyacınız varsa en pratik çözümdür. Table-Valued Parameters, stored procedure'lerle çalışmayı sevenler için güçlü bir alternatiftir. Batch INSERT ise basit ve orta ölçekli işlemler için yeterlidir. Hangi yöntemi seçerseniz seçin, batch size, transaction yönetimi ve indeks stratejileri gibi faktörleri göz önünde bulundurmayı unutmayın.