Ana içeriğe geç
Kesit SQL
İleri · Veri Mühendisliği

Artımlı yükleme (incremental load)

Watermark ile sadece yeni kayıtları işlemek.

Uygulamada aç, 5 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Her gece tüm tabloyu yüklemek ölçeklenmez

Milyarlarca satırlık bir olay tablosunu her gün baştan yüklemek pahalıdır. Artımlı yükleme, hedefte en son yüklenen zamanı (watermark) bulur ve sadece ondan yeni kayıtları ekler.

-- Hedef tablo: daha önce 15 Kasım'a kadar yüklenmiş
CREATE TABLE price_hist AS
SELECT * FROM price_updates WHERE updated_at < '2024-11-15';

-- Artımlı adım
INSERT INTO price_hist
SELECT * FROM price_updates
WHERE updated_at > (SELECT COALESCE(MAX(updated_at), '1900-01-01') FROM price_hist);

SELECT COUNT(*), MAX(updated_at) FROM price_hist;

Geç gelen veri

Bazı kayıtlar kaynağa gecikmeli düşer. Yaygın çözüm, watermark'tan biraz geriye giden bir pencereyi (ör. son 3 gün) her seferinde silip yeniden yüklemektir. Bu hem geç gelenleri yakalar hem de idempotenttir:

DELETE FROM fct_events WHERE event_date >= :baslangic;
INSERT INTO fct_events SELECT ... FROM raw_events WHERE event_date >= :baslangic;
dbt'dematerialized='incremental' ve {% if is_incremental() %} WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }}) {% endif %} kalıbı aynı mantığı uygular.

Derinleş: watermark, geç gelen veri ve kontrol tablosu

Watermark (su seviyesi), hedefe en son hangi noktaya kadar veri yüklendiğini gösteren değerdir: çoğunlukla bir zaman damgası, bazen artan bir kimlik. Artımlı iş her çalıştığında “watermark'tan sonrasını” okur ve sonunda watermark'ı ilerletir. Watermark'ı hedef tablodan MAX() ile türetmek basittir; ama üretimde genellikle ayrı bir kontrol tablosunda tutulur, çünkü hedef tablo silinip yeniden kurulabilir, birden çok kaynaktan beslenebilir veya boş olabilir.

CREATE TABLE etl_watermark (tablo VARCHAR(30), son_deger VARCHAR(19));
INSERT INTO etl_watermark (tablo, son_deger) VALUES ('price_updates', '2024-11-15 00:00:00');

-- Daha önceki çalıştırmalarla dolmuş hedef
CREATE TABLE price_hist (product_id INTEGER, new_price REAL, updated_at VARCHAR(19));
INSERT INTO price_hist
SELECT product_id, new_price, updated_at FROM price_updates
WHERE updated_at <= '2024-11-15 00:00:00';

-- Artımlı adım: watermark'tan sonrasını ekle, sonra watermark'ı ilerlet
INSERT INTO price_hist
SELECT product_id, new_price, updated_at FROM price_updates
WHERE updated_at > (SELECT son_deger FROM etl_watermark WHERE tablo = 'price_updates');

UPDATE etl_watermark
SET son_deger = (SELECT MAX(updated_at) FROM price_hist)
WHERE tablo = 'price_updates';

SELECT (SELECT COUNT(*) FROM price_hist) AS satir, son_deger FROM etl_watermark;

Watermark yalnızca yükleme başarıyla bittiğinde güncellenmelidir; aynı işlem (transaction) içinde ya da yüklemeden hemen sonra. Önce watermark'ı ilerletip sonra yüklemede hata alırsan aradaki kayıtlar sonsuza dek kaybolur.

> mı >= mı?

> aynı zaman damgasına sahip ama farklı çalıştırmalarda gelen kayıtları kaçırabilir; >= ise son anı iki kez yükler. Güvenli kombinasyon: >= ile oku, hedefe MERGE / NOT EXISTS ile yaz (tekrarı engelle).

Geç gelen veri

Lezzet Kurye'de 94 teslim siparişi, verildiği günden sonraki gün teslim edilmiş (gece yarısını aşan siparişler). Teslim tarihine göre günlük özet üreten bir iş öğlen çalışırsa o günün teslimlerinin bir kısmını henüz görmez. Çözüm, her çalıştırmada son birkaç günü silip yeniden yüklemektir (lookback penceresi). Pencere ne kadar geniş olmalı? Verinin gecikme dağılımına bak: gecikmelerin %99'u 2 gün içindeyse 3 günlük pencere yeterlidir.

SorunBelirtiÇözüm
Geç gelen kayıtGeçmiş günlerin sayıları sonradan artarLookback penceresiyle sil-yeniden yükle
Güncellenen kayıtDurum değişikliği hedefe yansımazupdated_at watermark'ı + MERGE
Silinen kayıtHedefte “hayalet” satırlarKaynakta soft delete bayrağı ya da periyodik tam karşılaştırma
Saat dilimiGün sınırında kayıp/çiftWatermark'ı UTC tut
Alıştırmalara geç (5)