Kesintisiz Şema Değişikliği İçin 6 Aşamalı Yol
Veritabanı şeması zamanla değişir. Gereksinimler olgunlaşır, ürünler gelişir, işletmeler birleşir, yeni sistemlerle bütünleşir veya farklı pazarlara açılır. Sorun, bu değişikliği veritabanına bağlı uygulamaları ve kullanıcıları kesintiye uğratmadan yapmaktır.
Azure SQL için önerilen yöntem, değişikliği tek seferde yapmak yerine aşamalara ayırmaktır. “Expand-and-contract” adı verilen bu yöntemde önce yeni yapı eklenir, eski ve yeni yapılar bir süre birlikte çalışır, ardından eski yapı kaldırılır.
Örnek: Name Alanını İkiye Ayırmak
Bir User tablosundaki Name alanını FirstName ve LastName olarak ayırmak istediğinizi düşünün. Son hedef basit görünür, ancak üretim ortamına güvenli biçimde ulaşmak için eski ve yeni uygulama sürümlerinin bir süre birlikte çalışabilmesi gerekir.
Bu yüzden değişiklik; yeni sütunların eklenmesi, iki yapıya birlikte yazılması, eski verilerin doldurulması, okumaların taşınması, eski sütuna yazmanın bırakılması ve son olarak eski şemanın kaldırılması şeklinde ilerler.
1. Aşama: Yeni Sütunları Ekleyin
İlk adım, mevcut uygulamanın kullandığı yapıya dokunmadan yeni sütunları eklemektir:
ALTER TABLE dbo.[User]
ADD
FirstName nvarchar(100) NULL,
LastName nvarchar(100) NULL;
Bu aşamada Name sütunu olduğu gibi kalır. Mevcut uygulama örnekleri bu sütunu okumayı ve yazmayı sürdürür. Yeni sütunlar sonraki aşamaları bekler.
Yeni sütunların NULL kabul etmesi bilinçli bir tercihtir. Mevcut satırlarda henüz bu alanlara ait değer bulunmadığı için ilk anda zorunlu değer istemek, basit bir ekleme işlemini veri taşıma sorununa çevirebilir.
Sıralama burada önemlidir: Önce veritabanı değişikliği dağıtılmalı, tüm üretim veritabanları hem eski hem de yeni şemayı tanıdıktan sonra uygulama kodu güncellenmelidir.
2. Aşama: Eski ve Yeni Sütunlara Birlikte Yazın
Veritabanı iki yapıyı da desteklemeye başladığında uygulama, kullanıcı adını üç sütuna birlikte yazabilir:
user.Name = $"{user.FirstName} {user.LastName}";
user.FirstName = firstName;
user.LastName = lastName;
Her ekleme veya güncelleme işleminde Name, FirstName ve LastName değerleri aynı anda güncel tutulmalıdır. Böylece eski uygulama örnekleri Name alanını okumayı sürdürürken yeni uygulama örnekleri yeni sütunları kullanabilir.
Yeni sütunlardan okumaya geçmeden önce çift yönlü yazma başlatılmalıdır. Mevcut satırlar henüz doldurulmadığı için FirstName ve LastName değerleri NULL olabilir. Çift yazma, bu aşamadan sonra değiştirilen verilerin iki temsilinde de güncel kalmasını sağlar.
Senkronizasyon için tetikleyici kullanılabilir, ancak mümkünse geçiş mantığını uygulamada tutmak daha uygundur. Uygulama değişikliğin anlamını bildiği için mantık görünür kalır ve geçiş tamamlandığında kaldırılması kolaylaşır. Birden fazla uygulama doğrudan tabloya yazıyor ve hepsini aynı anda güncellemek mümkün değilse tetikleyici uygun bir seçenek olabilir.
Yazma işlemleri zaten saklı yordamlar üzerinden yürüyorsa bu yordamları güncellemek de pratik bir yoldur. Yordam yeni alanları kabul edip eski Name alanını doldurmaya devam edebilir. Ancak yalnızca geçişi kolaylaştırmak için yeni bir soyutlama katmanı eklemek, daha sonra dağıtılması ve kaldırılması gereken ek bir yapı yaratır.
3. Aşama: Mevcut Satırları Doldurun
Yeni yazmalar iki temsili de güncel tuttuktan sonra, geçişten önce var olan satırlar doldurulabilir:
UPDATE dbo.[User]
SET
FirstName = LEFT(Name, CHARINDEX(' ', Name + ' ') - 1),
LastName = LTRIM(SUBSTRING(
Name,
CHARINDEX(' ', Name + ' ') + 1,
LEN(Name)
))
WHERE FirstName IS NULL
OR LastName IS NULL;
Bu örnekteki ad ayrıştırma mantığı basittir. Gerçek adlarda ön ekler, son ekler, birleşik soyadları, tek kelimelik adlar ve farklı adlandırma biçimleri bulunabilir. Bu nedenle dönüşüm mantığı ayrıca doğrulanmalı, her durumda T-SQL ile uygulanmasının uygun olmayabileceği göz önünde bulundurulmalıdır.
Üretimde bir başka konu da tek seferde ne kadar verinin güncelleneceğidir. Büyük bir UPDATE işlemi kilitleri uzun süre tutabilir, işlem günlüğünü büyütebilir ve sistemi gereksiz yere zorlayabilir. Büyük tablolar için işlem parçalar halinde yürütülebilir:
WHILE 1 = 1
BEGIN
UPDATE TOP (1000) dbo.[User]
SET
FirstName = LEFT(Name, CHARINDEX(' ', Name + ' ') - 1),
LastName = LTRIM(SUBSTRING(
Name,
CHARINDEX(' ', Name + ' ') + 1,
LEN(Name)
))
WHERE FirstName IS NULL
OR LastName IS NULL;
IF @@ROWCOUNT = 0
BREAK;
END
Çift yazmanın önce başlatılması, geçmiş satırlar doldurulurken yeni eklenen veya güncellenen satırların iki temsilde de korunmasını sağlar. Bu işlem için uygulamayı durdurmak gerekmez.
4. Aşama: Okumaları Yeni Sütunlara Taşıyın
Tüm satırlardaki yeni alanlar doldurulup yeni yazmalar bu alanları güncel tuttuğunda, uygulama okumaları yeni şemaya taşınabilir:
SELECT
Id,
FirstName,
LastName,
Email
FROM dbo.[User];
Bu adım bir temizlik işi gibi görülmemeli, ayrı bir dağıtım aşaması olarak ele alınmalıdır. Eski uygulama örnekleri veya başka tüketiciler hâlâ Name sütununa bağlı olabilir. Bu nedenle okumalar kademeli olarak taşınmalı ve geçiş sırasında ortaya çıkan sorunlar izlenmelidir.
Aşamalı dağıtım, canary dağıtımı veya özellik bayrakları destekleniyorsa bu aşamada kullanılabilir. Yeni ve eski uygulama biçimleri aynı anda veritabanı tarafından desteklendiği için tüm tüketicileri tek seferde değiştirmek gerekmez.
Name sütununa ait okuma izinlerini hemen kaldırmak, bağımlılıkları keşfetmek için riskli bir yoldur. Raporlar, işler, betikler veya eski uygulama örnekleri hâlâ bu alanı kullanıyor olabilir. Daha güvenli yol, kullanımı gözlemlemek, bilinen tüketicileri güncellemek ve bağımlılıkların sona erdiğinden emin olana kadar eski sütunu okunabilir bırakmaktır.
Query Store, eski sütuna referans veren yakın tarihli sorguları bulmak için başlangıç noktası olabilir. Uygulama günlükleri, veritabanı günlükleri, bağımlılık bilgileri ve geçici Extended Events kullanımı da yardımcı olur. Tek bir yöntem tüm tüketicileri göstermeyebileceği için ortamda uygun araçlar birlikte değerlendirilmelidir.
Uygulamanın yanı sıra raporlar, ETL işleri, dışa aktarımlar, betikler, zamanlanmış işler, not defterleri ve alt sistemler de kontrol edilmelidir.
5. Aşama: Name Sütununa Yazmayı Bırakın
Uygulama okumaları yeni sütunlara taşınıp diğer tüketicilerin geçişi için yeterli süre beklendikten sonra çift yazma mantığı kaldırılabilir:
user.FirstName = firstName;
user.LastName = lastName;
Bu noktada Name sütununun eski haliyle kalması beklenir. Ancak sütun henüz silinmemelidir. Bir süre daha yerinde bırakılması, uygulama, rapor, iş veya alt sistemlerin eski değer güncellenmeyi bıraktığında beklenmedik biçimde etkilenip etkilenmediğini görmeyi sağlar.
Buradaki ayrım önemlidir: Name silinmemiş, kullanımdan kaldırılmıştır. Yeni şemanın doğruluğu korunurken eski sütun bir uyumluluk arabelleği olarak tutulur.
6. Aşama: Doğrulayın ve Eski Şemayı Kaldırın
Son adımdan önce yeni durum doğrulanmalıdır. Beklenen satırlarda yeni alanların dolu olduğu kontrol edilmeli, beklenmeyen NULL değerleri incelenmeli, raporların ve alt sistemlerin yeni yapıya geçtiği doğrulanmalıdır. Yeni sütunlara ait son kısıtlar veya indeksler de bu aşamada eklenebilir.
Doğrulama tamamlandığında eski sütun kaldırılabilir:
ALTER TABLE dbo.[User]
DROP COLUMN Name;
Bu işlem, expand-and-contract yaklaşımının “contract” bölümüdür. Şema önce genişletilir, eski ve yeni yapılar birlikte çalıştırılır, yazmalar ve okumalar taşınır, veriler doldurulur, geçiş doğrulanır ve ancak bundan sonra eski yapı kaldırılır.
Geçiş doğru sırayla yapıldıysa sütunu kaldırma adımı sürpriz yaratmaz. Çünkü bu noktada hiçbir tüketicinin eski sütuna bağlı kalmaması gerekir.
Sonuç: Asıl Değer Sıralamada
Örnek yalnızca bir ad sütununun ayrıştırılmasını ele alıyor, ancak yöntem daha geniş şema değişikliklerinde de kullanılabilir. Önce yeni yapı eklenir, eski ve yeni temsiller birlikte çalıştırılır, yazmalar taşınır, mevcut veri doldurulur, okumalar güncellenir, eski yazmalar durdurulur ve son olarak eski yapı kaldırılır. Kesintisiz geçiş bu sıraya dayanır.
Tek tek SQL ifadeleri kolay olabilir. Zor olan, bunları doğru sırayla ve her aşamadaki uyumluluk gereksinimlerini gözeterek uygulamaktır.







Yorum gönder