Veritabanı ve veri aktarımı rehberi
Database Migration Nedir? Veritabanı Taşıma, Doğrulama ve Geri Dönüş
Database migration (DB migration), bir veritabanındaki verinin ve nesnelerin başka bir sunucuya, sürüme ya da veritabanı ürününe planlı biçimde taşınmasıdır; Türkçede veritabanı taşıma ya da veritabanı migrasyonu da denir. İş "kopyala ve aç" değildir: hangi nesnelerin taşınacağı, veri tiplerinin nasıl eşleneceği, sonucun nasıl doğrulanacağı ve sorun çıkarsa nasıl geri dönüleceği taşımadan önce yazılı hale gelmelidir.
Son güncelleme: 30 Eylül 2026. Örnek tablo ve sütun adları (ornek_siparis vb.) kurgusaldır; kendi şemanıza uyarlayın.
Database migration neyi anlatır, neyi anlatmaz?
Migration'ın sonunda kaynak veritabanı devre dışı kalır ve uygulamalar hedefe bağlanır. Bu yüzden yakın görünen üç işten ayrılır: yedekleme aynı ürüne geri dönmek için alınan kopyadır; replikasyon iki veritabanını bir arada ve senkron tutar, kaynağı kapatmak amacı taşımaz; günlük ETL ise veriyi raporlama gibi başka bir amaç için düzenli olarak hedefe taşır ve kaynak yerinde çalışmaya devam eder.
"DB migration" ifadesi bir de uygulama geliştirmede kullanılır. Flyway veya Liquibase gibi araçlarla uygulamanın tablo yapısı sürüm sürüm değiştirilir; buna şema migration'ı denir ve veriyi başka bir veritabanına taşımaz. Bu sayfa ilk anlamı, yani veritabanının kendisinin taşınmasını ele alır.
Hangi taşıma yöntemi: tek seferlik, artımlı ya da CDC?
Yöntemi belirleyen soru, kaynağın taşıma sürerken ne kadar süre yazmaya açık kalacağıdır. Kesinti toleransınız yüksekse en basit yöntem yeterlidir.
| Yöntem | Nasıl çalışır? | Kesinti | Uygun durum ve risk |
|---|---|---|---|
| Tek seferlik (full load) | Kaynak yazmaya kapatılır, tüm veri bir kerede aktarılır, uygulamalar hedefe çevrilir. | Aktarım süresi kadar | Hacim küçükse ya da gece/hafta sonu penceresi varsa. Risk: aktarım pencereye sığmazsa taşıma yarıda kalır. |
| Full load + artımlı yükleme (incremental load) | Büyük kısım önceden aktarılır; geçiş günü yalnız o günden sonra değişen satırlar taşınır. | Yalnız son fark kadar | Tablolarda güvenilir bir değişiklik işareti (güncelleme tarihi, artan anahtar) varsa. Risk: silinen satırlar bu işaretle görünmez. |
| CDC ile sürekli senkron geçiş | Kaynaktaki her değişiklik (ekleme, güncelleme, silme) kaydedilip hedefe uygulanır; geçiş anında iki taraf eşitlenir. | Çok kısa, yazmanın durdurulduğu an | Kesintinin kabul edilmediği sistemlerde. Risk: kaynakta değişiklik kaydını okuma yetkisi ve ek işletim yükü gerekir. |
| Günlük ETL (migration değil) | Veri düzenli olarak dönüştürülüp raporlama hedefine yüklenir. | Yok; kaynak çalışmaya devam eder | Amaç kaynağı kapatmak değil, veriyi başka bir amaçla kullanmaksa. Bkz. ETL nedir? |
Taşımadan önce çıkarılacak envanter
Taşımanın en sık atlanan kısmı tablo olmayan nesnelerdir. Tablolar sorunsuz gelir, ama gece çalışan bir iş ya da başka bir veritabanına giden bir bağlantı unutulursa sorun taşıma bittikten sonra çıkar. Aşağıdaki listeyi her kaynak şema için doldurun.
- Tablolar, indeksler, kısıtlar: adet, en büyük 10 tablo, partition kullanımı.
- Görünümler ve sequence'ler: sequence'lerin son değeri hedefte devam ettirilmeli, yoksa yeni kayıtlar çakışır.
- Trigger, saklı yordam, fonksiyon ve paketler: kaynak ürüne özgü dil (PL/SQL gibi) hedefte elle ya da araçla yeniden yazılır; en pahalı kalem çoğunlukla budur.
- Zamanlanmış işler: veritabanı içinde çalışan ve dışarıdan (cron, iş zamanlayıcı) tetiklenenler ayrı ayrı.
- Harici bağımlılıklar: veritabanı bağlantıları (dblink), dış tablolar, dosya yolları, posta ya da web servis çağrıları.
- Kullanıcılar, roller, yetkiler: uygulama hesapları ve salt okunur raporlama hesapları.
- Bağlantı dizesini kullananlar: uygulamalar, raporlar, BI araçları, ETL işleri ve elle çalışan betikler. Geçiş günü hepsinin yeni adrese çevrileceği bir liste olmalı.
- Boyut ve büyüme: toplam hacim, günlük artış, en büyük tabloların satır sayısı.
- Kesinti toleransı: iş biriminin kabul ettiği en uzun yazma kesintisi, yazılı olarak.
Oracle kaynaklarda envanterin ilk dökümünü sözlük görünümlerinden alabilirsiniz (örnek şema adını değiştirin):
-- Oracle: şemadaki nesne türleri ve adetleri
SELECT object_type, COUNT(*) AS adet
FROM all_objects
WHERE owner = 'ORNEK_SEMA'
GROUP BY object_type
ORDER BY adet DESC;
-- Oracle: veritabanı bağlantıları (dblink) ve zamanlanmış işler
SELECT owner, db_link, host FROM all_db_links;
SELECT owner, job_name, enabled FROM all_scheduler_jobs WHERE owner = 'ORNEK_SEMA';Oracle'dan PostgreSQL'e veri tipi eşleme
Bu yönde taşıma en sık sorulanıdır ve şema çevirisinin büyük kısmı veri tiplerinde biter. Aşağıdaki tablo PostgreSQL ve Oracle resmî dokümanlarına ve Ora2Pg'nin varsayılan eşlemesine dayanır; tabloyu başlangıç noktası sayın, son kararı sütundaki gerçek veriye bakarak verin. Araç ve sürece dair ayrıntı için Oracle'dan PostgreSQL'e veri aktarımı yazısına bakabilirsiniz.
| Oracle | PostgreSQL | Dikkat |
|---|---|---|
| NUMBER (duyarlık yok) | numeric | Oracle'da duyarlıksız NUMBER ondalık da tutabilir. Sütunun yalnız tam sayı içerdiğini sorguyla doğrularsanız integer veya bigint seçilebilir. |
| NUMBER(p,s), s > 0 | numeric(p,s) | Parasal ve oranlı alanlarda real/double precision seçmeyin; kayan nokta yuvarlama farkı yaratır. PostgreSQL numeric için en çok 1000 duyarlık tanımlanabilir, Oracle'ın 38 sınırı rahatça sığar. |
| NUMBER(p,0), küçük tam sayı | p en çok 4: smallint; en çok 9: integer; en çok 18: bigint; 18'den büyük: numeric(p,0) | Eşikler PostgreSQL aralıklarından gelir (smallint 32767, integer 2147483647, bigint 9223372036854775807). Ora2Pg de PG_INTEGER_TYPE ayarıyla duyarlığa göre bu üç tipi seçer. |
| VARCHAR2(n) | varchar(n) veya text | Oracle'da n, sütun tanımına göre bayt ya da karakter olabilir (BYTE/CHAR); PostgreSQL'de karakterdir. Bayt tanımlı sütunlarda n'yi yeniden hesaplayın. PostgreSQL dokümanına göre char(n)'in diğer ürünlerdeki hız avantajı yoktur, çoğunlukla üç tipin en yavaşıdır; varchar veya text tercih edilir. |
| CHAR(n) | varchar(n) (ya da char(n)) | İkisi de boşlukla doldurur. Uygulama sondaki boşluğa güveniyorsa char(n), güvenmiyorsa varchar tercih edilir. |
| DATE | timestamp(0) | Oracle DATE saat, dakika ve saniye de saklar. PostgreSQL date seçilirse saat bilgisi silinir. Ora2Pg varsayılanı timestamp(0)'dır. |
| TIMESTAMP(n) | timestamp(n) | Oracle 9, PostgreSQL 6 kesirli saniye basamağına kadar çıkar. 6'dan fazla basamak kullanıyorsanız taşımada kırpılır. |
| TIMESTAMP WITH TIME ZONE | timestamptz | Oracle değerle birlikte ofseti (ya da bölge adını) saklar. PostgreSQL değeri UTC olarak saklar, oturum saat dilimine göre gösterir ve girişte verilen ofseti korumaz. Ofsete ihtiyaç varsa ayrı sütun açın. |
| CLOB, NCLOB, LONG | text | Ora2Pg varsayılanı. PostgreSQL metin değerini yaklaşık 1 GB'a kadar tutar; bundan büyük CLOB'lar için ayrı plan gerekir. |
| BLOB, LONG RAW, RAW | bytea | RAW(16) ve RAW(32) için Ora2Pg varsayılanı uuid'dir; bu yalnız sütun gerçekten GUID tutuyorsa doğrudur. |
Boş string tuzağı. Oracle dokümanı sıfır uzunluklu karakter değerini NULL saydığını belirtir. PostgreSQL'de '' ile NULL ayrı değerlerdir. Uygulama boş metin gönderiyorsa, hedefte NULL yerine '' birikir; NULL sayan sorgular ve raporlar farklı sonuç verir. NULL ile metin birleştiren ifadelerde de PostgreSQL sonucu NULL döndürür. Bu yüzden doğrulama sorgularında sütun bazlı NULL sayısına bakılması gerekir.
Taşımadan sonra kaynakla hedefi aynı sorguyla karşılaştırın
Mutabakatın kuralı basittir: aynı sorgu iki tarafta çalışır, çıktılar satır satır karşılaştırılır. Aşağıdaki sorgu Oracle'da da PostgreSQL'de de aynen çalışır. Tablo ve sütun adları örnektir; önce kritik tablolarla, sonra tüm tablolarla tekrarlayın.
-- Kaynakta (Oracle) ve hedefte (PostgreSQL) aynı sorgu
SELECT COUNT(*) AS satir_sayisi,
SUM(tutar) AS toplam_tutar,
TO_CHAR(MIN(siparis_tarihi), 'YYYY-MM-DD HH24:MI:SS') AS ilk_tarih,
TO_CHAR(MAX(siparis_tarihi), 'YYYY-MM-DD HH24:MI:SS') AS son_tarih,
COUNT(*) - COUNT(musteri_kodu) AS musteri_kodu_null,
COUNT(DISTINCT musteri_kodu) AS musteri_sayisi
FROM ornek_siparis;Tarihi saat dahil yazdırmak bilinçlidir: Oracle istemcileri DATE'i tarih biçimi ayarına göre saatsiz gösterebilir; saat kaybını yakalayan bu ifadedir. Toplam fark çıkarsa günlere bölün. Gün kırpma fonksiyonu iki üründe farklı yazılır:
-- Oracle
SELECT TRUNC(siparis_tarihi) AS gun, COUNT(*) AS satir_sayisi, SUM(tutar) AS toplam_tutar
FROM ornek_siparis
GROUP BY TRUNC(siparis_tarihi)
ORDER BY gun;
-- PostgreSQL
SELECT CAST(siparis_tarihi AS date) AS gun, COUNT(*) AS satir_sayisi, SUM(tutar) AS toplam_tutar
FROM ornek_siparis
GROUP BY CAST(siparis_tarihi AS date)
ORDER BY gun;
-- PostgreSQL: Oracle'daki NULL yerine boş string yazılmış mı?
SELECT COUNT(*) FILTER (WHERE aciklama = '') AS bos_metin,
COUNT(*) FILTER (WHERE aciklama IS NULL) AS null_sayisi
FROM ornek_siparis;İlk sorgudaki farkları şu sırayla okuyun: satır sayısı farklıysa yükleme eksik ya da mükerrerdir; satır sayısı aynı ama toplam farklıysa sayısal tip eşlemesi ya da dönüşüm kuralı sorunludur; yalnız NULL sayısı farklıysa yukarıdaki boş string davranışına bakın; yalnız son tarih farklıysa saat kaybı veya saat dilimi kayması vardır. Sequence değerlerini de karşılaştırın: hedefte bir sonraki değer, tablodaki en büyük anahtardan büyük olmalıdır.
Geri dönüş kararını taşımadan önce yazın
Geçiş gecesi yorgun bir ekibin "devam mı, geri mi?" sorusunu tartışması pahalıdır. Kararı önceden yazılı kabul ölçütü olarak belirleyin; ölçütlerin değerlerini sayıyla ve sorumlu kişiyle kaydedin. Bu sayfadaki hiçbir eşik evrensel değildir, her sistemin iş kuralı farklıdır.
- Mutabakat farkı: kritik tablolarda açıklanamayan satır ya da toplam farkı ölçütü (hangi tablolarda sıfır fark şart, hangilerinde kabul edilen açıklamalı fark).
- Kritik sorgu süresi: iş için önemli sorguların kabul edilen en uzun süresi; deneme taşımasında aynı sorgularla ölçülür.
- Uygulama hata oranı: geçişten sonraki ilk izleme diliminde kabul edilen hata düzeyi.
- Kesinti penceresi: pencerenin bitiminden kaç dakika önce hâlâ doğrulama tamamlanmamışsa geri dönüleceği.
- Yetki ve güvenlik: kritik bir uygulama hesabının ya da raporun çalışmaması gibi, telafisi beklenmeyecek durumlar.
Geri dönüşün teknik koşulu şudur: hedefe ilk yazma yapılana kadar kaynağı salt okunur tutmak yeterlidir. Hedefe yazma başladıktan sonra geri dönmek, o yazmaları kaynağa taşıyacak bir yol ister. Bu yolu (tersine aktarım ya da geçiş sonrası belirli bir süre çift yazma) deneme taşımasında da sınayın; geri dönüşü hiç denememiş bir plan, plan sayılmaz.
Veritabanı taşıma hizmeti aldığınızda teslim edilmesi gerekenler
Veritabanı taşıma hizmeti, yukarıdaki işlerin bir ekip tarafından üstlenilmesidir. Teklif ya da sözleşme aşamasında yalnız "taşıma yapılır" cümlesiyle yetinmeyin; şu çıktıların teslimini isteyin.
- Nesne ve bağımlılık envanteri, taşınmayacak nesnelerin gerekçesiyle birlikte.
- Veri tipi eşleme tablosu ve farklı seçilen sütunların kararı.
- Gerçek veriyle yapılmış en az bir deneme taşımasının süresi ve mutabakat çıktısı.
- Yazılı kabul ve geri dönüş ölçütleri, geçiş günü adım listesi.
- Geçişten sonra izleme dönemi ve bu dönemde kimin neye cevap vereceği.
Kendi ortamınız için bu çıktıların nasıl hazırlanacağını konuşmak isterseniz veritabanı veri aktarımı danışmanlığı sayfasına, taşıma öncesi mevcut veritabanı durumunu görmek için database health check sayfasına bakabilirsiniz.
Sık sorulan sorular
Database migration nedir?
Database migration, bir veritabanının verisini ve nesnelerini (tablo, indeks, görünüm, saklı yordam vb.) başka bir sunucuya, sürüme ya da veritabanı ürününe planlı biçimde taşımaktır. Envanter, eşleme, deneme taşıması, doğrulama ve geri dönüş planı bu işin parçasıdır.
DB migration ile Flyway veya Liquibase migration'ı aynı şey mi?
Hayır. Flyway ve Liquibase gibi araçlar uygulamanın şema değişikliklerini sürümler halinde uygular; veriyi bir veritabanından diğerine taşımaz. Bu sayfa, veritabanının kendisini başka bir ortama taşıyan migration'ı anlatır.
Veritabanı taşıma ne kadar sürer?
Süreyi hacim, ağ hızı, indeks sayısı ve taşıma sırasında yapılan dönüşümler belirler; bu yüzden genel bir süre vermek doğru olmaz. Gerçek veriyle yapılan bir deneme taşıması süreyi ölçmenin tek güvenilir yoludur ve kesinti penceresi bu ölçüme göre planlanmalıdır.
Oracle DATE sütununu PostgreSQL'de neden timestamp yapıyoruz?
Oracle DATE tipi tarihin yanında saat, dakika ve saniyeyi de saklar. PostgreSQL date tipi ise yalnız tarih tutar, yani saat bilgisi kaybolur. Bu nedenle Ora2Pg de varsayılan olarak DATE sütununu timestamp(0) ile eşler; yalnız tarih tuttuğunu doğruladığınız sütunlarda date seçebilirsiniz.
Taşıma bittikten sonra verinin eksiksiz geldiğini nasıl anlarım?
Kaynakta ve hedefte aynı özet sorgusunu çalıştırıp sonuçları karşılaştırın: satır sayısı, parasal sütunların toplamı, tarih aralığı ve sütun bazlı NULL sayısı. Fark çıkarsa tablo bazında araştırılır; açıklanamayan fark geçişi durdurma nedenidir.
Geri dönüş ne zamana kadar mümkündür?
Hedefe ilk kez yeni yazma yapılana kadar kaynağı salt okunur tutarak kolayca geri dönebilirsiniz. Hedefe yazma başladıktan sonra geri dönüş, o yazmaları kaynağa taşıyacak ikinci bir veri yolu gerektirir; bu yol önceden planlanmamışsa geri dönüş veri kaybı anlamına gelebilir.



