SQL Server'da Veritabanları Arası Veri Güncelleme: Cross-Database UPDATE Rehberi
Master-Slave ERP kurulumlarında şubeler arası veri nasıl senkronize edilir? SQL Server'da Cross-Database UPDATE, Batch Processing ve Linked Server...
İş Problemi: “Merkezde Değişen Ünvan Adana’ya Neden Gitmedi?”
Özellikle inşaat, perakende veya grup şirket yapıları kullanan büyük çaplı Mikro ERP kurguları genellikle Tek Veritabanı (Single DB) yerine “Multi-Tenant / Multi-Database” tercih eder. (Örn: MikroDB_Holding, MikroDB_A_Sirketi, MikroDB_B_Sirketi vb.)
Ancak bu mimarinin karanlık bir yüzü vardır: Veri Uyumsuzluğu.
Muhasebe veya satınalma departmanı Master (Ana) şirkette bir Cari Ünvanı’nı (cari_unvan1) değiştirir, Vergi Dairesi bilgisini günceller. Fakat bu veri alt şubeye otomatik olarak gitmez. Bunun sonucunda, Adana şubesi fatura kesmeye çalıştığında, e-Fatura entegratöründe VKN/Ünvan uymaz ve e-Fatura iptal veya red yer. Şirket itibar zedeleyici bir sürece girer.
Neden Geleneksel Çözümler Batırır? Kullanıcılar genellikle DB üzerine bir TRIGGER yazar. “Şu veritabanında UPDATE oldu mu diğerine de at” sistemi, SQL sunucusunun IO (Input/Output) performansını tüketir ve bir şube DB’sinde kilitlenme (Deadlock) yaşandığında ana üretim hattını da kilitler!
Çözüm: Asenkron Toplu (Batch) Senkronizasyon Algoritması
Bizim AstaFlow tarzı Multi-DB yapılarında tavsiye ettiğimiz olay, “Transaction Riskini Minimize Eden Programlanmış Çapraz Güncelleme” mimarisidir. Bunu SQL Server Agent içerisine konulan periyodik bir “Sync Job” (Örn: Her 15 dakikada bir) ile yaparsanız sıfır hata ve kesintisizlik elde edersiniz.
Aşağıda veritabanını felç etmeden (Batch bloklarıyla) güncelleme yapan bir Kurumsal “Cross-DB Sync” yordamını görebilirsiniz:
-- GÜVENLİ CROSS-DB SENKRONİZASYON STORED YORDAMI
SET NOCOUNT ON;
DECLARE @KaynakDB NVARCHAR(128) = 'MikroDB_Merkez';
DECLARE @HedefDB NVARCHAR(128) = 'MikroDB_Adana';
-- Hangi tablonun hangi sütunları denetlenecek?
-- (Örnekte Müşteri Sicil Kartları-CARI_HESAPLAR Master alınıyor)
DECLARE @SQL_SENKRON NVARCHAR(MAX) = N'
-- TRANSACT-SQL ERROR HANDLING AÇILIYOR
BEGIN TRY
BEGIN TRANSACTION;
-- ADIM 1: Sadece "Farklı" olan kayıtları hedefleyip performansı artırıyoruz
-- Hedef tablodaki Ünvan veya VKN, Ana tablodaki ile aynı DEĞİLSE tetiklenir.
UPDATE Hedef
SET
Hedef.cari_unvan1 = Kaynak.cari_unvan1,
Hedef.cari_vdaire_no = Kaynak.cari_vdaire_no
FROM [' + @HedefDB + N'].dbo.CARI_HESAPLAR Hedef
INNER JOIN [' + @KaynakDB + N'].dbo.CARI_HESAPLAR Kaynak
ON Hedef.cari_kod = Kaynak.cari_kod
WHERE
ISNULL(Hedef.cari_unvan1, '''') <> ISNULL(Kaynak.cari_unvan1, '''')
OR
ISNULL(Hedef.cari_vdaire_no, '''') <> ISNULL(Kaynak.cari_vdaire_no, '''');
-- Eğer etkilenen satır yoksa işlem şeffafça devam eder.
DECLARE @RowAffected INT = @@ROWCOUNT;
COMMIT TRANSACTION;
PRINT ''✅ Senkronizasyon BAŞARILI. Güncellenen Kayıt: '' + CAST(@RowAffected AS NVARCHAR);
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
-- Hatayı Log tablonuza yazın veya SysAdmin''e alert çıkartın
PRINT ''❌ KRİTİK SYNC HATASI'';
PRINT ''Error Message: '' + ERROR_MESSAGE();
END CATCH
';
EXEC sp_executesql @SQL_SENKRON;
Performans / Ölçekleme (Lock ve Timeout Sorunsalı)
Eğer Cari Hesaplar tablonuzda 300.000 kayıt varsa ve siz yukarıdaki gibi salt UPDATE atarsanız, Database Engine tüm hedef tabloya Exclusive Lock (X) uygular. Başka bir memur o saniyede Adana şubesine fatura kaydedemez, SQL Timeout yer.
Nasıl Çözülür (Batch Update Senaryosu): Yüz binlerce satırlık farklarda, 5000 satırlık bloklara ayırıp WAITFOR DELAY (nefes alma) kurgusu eklenerek tablo lock baypas edilebilir:
-- DÖNGÜSEL BATCH UPDATE (Özet Mantık)
WHILE (1=1)
BEGIN
UPDATE TOP (5000) Hedef SET Hedef.Unvan = Kaynak.Unvan ...
IF @@ROWCOUNT = 0 BREAK;
WAITFOR DELAY '00:00:01'; -- 1 Saniye Sunucunun nefes almasına izin ver!
END
Edge Cases (İstisnai Durumlar) ve Mimari Tehlikeler
- Farklı Sunucularda Olma Durumu (Linked Servers): Eğer Merkez İstanbul’da ayrı bir Cloud makinesinde, Adana şubesi kendi binasındaki bir sunucuda ise
[MikroDB_Merkez].dbo.Carişeklinde direkt bağlanılamaz! SQL Server’daSP_ADDLINKEDSERVERile ağ geçidi tanımlanmalıdır. Ancak Linked Server üzerinden Cross-DB UPDATE yapmak ağ gecikmesi (Latency) nedeniyle son derece risklidir; işlem koptuğunda veri yarı yolda kalabilir. Bunun yerine “Veri Aktarımını Yapan API” (Microservice) tercih edilmelidir. - Kayıt “Yoksa” (INSERT) Olasılığı: Yukardaki senaryo
INNER JOINtabanlı bir Edit (UPDATE) mantığıdır. Merkezde açılan yeni bayi henüz şubede hiç açılmadıysa? O zamanMERGE INTOSQL komutuyla “Bulursan Update et, Bulamazsan Arkasına Insert at” mantığı devreye alınmalıdır. - Collation (Dil Karakter Seti) Sorunları: Eğer Merkez şube veritabanı
Turkish_CI_ASile açılmış, Şube DBLatin1_General_CI_ASile kurulmuşsa (kurulum hatası), Cross-DB Join attığınız esnada “Cannot resolve collation conflict” SQL patlaması yaşarsınız. Join bloklarınaCOLLATE DATABASE_DEFAULTeklemeniz hayat kurtarır.
Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)
- AstaFlow Case Study: Asta Stoka Yansıyan Ana Şube Veri Senkronizasyonu
- İlgili Çözüm: SQL Server’ı Cloudflare Arkası Web’e Açma Reçetesi