23 puan yazan GN⁺ 2026-01-23 | 4 yorum | WhatsApp'ta paylaş
  • Veri kurtarma ve mevzuata uyum için archived_at sütununa dayalı soft delete sık kullanılır, ancak zamanla karmaşıklık ve verimsizlik büyür
  • Bu yaklaşım sorguları, indeksleri, migration'ları ve geri yükleme mantığını karmaşıklaştırır; ayrıca arşivlenen verilerin çoğu bir daha okunmadığı için veritabanında gereksiz yük oluşturur
  • Alternatif olarak uygulama olayı tabanlı arşivleme, trigger tabanlı arşivleme ve WAL (Change Data Capture) tabanlı arşivleme önerilir
  • Her yaklaşım operasyonel karmaşıklık, altyapı gereksinimleri ve geri yükleme kolaylığı açısından farklılık gösterir; özellikle WAL tabanlı yöntem Kafka gibi harici sistemlerle entegrasyon gerektirir
  • Yeni bir projede trigger tabanlı yaklaşım, basitlik ve bakım kolaylığı açısından en dengeli seçimdir

Soft delete'in sorunları

  • Veriler genellikle deleted boolean'ı veya archived_at timestamp sütunu kullanılarak mantıksal olarak silinir
    • Müşteri veriyi yanlışlıkla sildiğinde geri getirme mümkündür
    • Mevzuat ya da denetim amaçlarıyla saklama zorunluluğu da olabilir
  • Ancak archived_at sütunu, sorgular, operasyonlar ve uygulama kodu genelinde karmaşıklık yaratır
    • Arşivlenen verilerin çoğu yeniden okunmaz
    • API davranış sorunları veya otomasyon araçları (Terraform vb.) nedeniyle milyonlarca gereksiz satır birikebilir
  • Arşiv verisini temizleme işi yapılandırılmazsa veritabanı yedekleme ve geri yükleme sırasında performans düşüşü yaşanır
  • Sorgu ve indekslerde arşiv verisinin filtrelenmesi gerekir ve veri sızıntısı riski vardır
  • Migration sırasında eski veriyi işlemek veya varsayılan değerleri değiştirmek zordur
  • Geri yükleme mantığı karmaşıklaşır; harici sistem çağrıları gerektiğinde hata çıkabilir
  • Sonuç olarak archived_at yaklaşımı basit görünse de uzun vadede bakım maliyeti yüksektir

Uygulama seviyesi arşivleme

  • Silme sırasında bir event yayınlanır ve bu event SQS'ye gönderilerek başka bir servis tarafından S3'e arşivlenir
  • Avantajlar
    • Ana veritabanı ve uygulama kodu sadeleşir
    • Harici kaynakların temizliği asenkron olarak işlenir, böylece performans ve güvenilirlik artar
    • JSON biçiminde serileştirilerek uygulama dostu bir yapıda arşivlenebilir
  • Dezavantajlar
    • Uygulama kodundaki hatalar nedeniyle arşiv verisi kaybolabilir
    • Mesaj kuyruğu gibi bileşenlerle operasyonel altyapı karmaşıklığı artar
    • S3'teki arşiv verisi için arama ve geri yükleme araçları gerekir

Trigger tabanlı arşivleme

  • Silme öncesi trigger, satırı ayrı bir archive tablosuna JSON olarak kopyalar
    • Örnek tablo: archive(id, table_name, record_id, data, archived_at, caused_by_table, caused_by_id)
  • Foreign key silmelerinde (cascade) silme nedenini izlemek için oturum değişkenleri (archive.cause_table, archive.cause_id) kullanılır
    • Hangi üst kaydın alt veriyi sildiği sorgulanabilir
  • Avantajlar
    • Canlı tablolar temiz kalır, archived_at sütununa gerek olmaz
    • Arşiv tablosunu temizlemek (WHERE archived_at < NOW() - INTERVAL '90 days') kolaydır
    • Sorgu ve indeks verimliliği korunur, migration'lar sadeleşir
    • Yedek boyutu azalır
  • Arşiv tablosu ayrı bir tablespace içinde ya da zaman tabanlı partitioning ile yönetilebilir

WAL (Change Data Capture) tabanlı arşivleme

  • PostgreSQL'in WAL log'ları okunarak silme event'leri harici sistemlere stream edilir
    • Temsili araç: Debezium (Kafka ile entegre)
    • Örnek akış: PostgreSQL → Debezium → Kafka → Consumer → Archive Storage
  • Daha hafif alternatifler
    • pgstream: WAL'ı doğrudan webhook'a veya mesaj kuyruğuna gönderir
    • wal2json: WAL'ı JSON olarak çıktılar
    • pg_recvlogical: PostgreSQL'in yerleşik logical replication aracı
  • Operasyonel karmaşıklık
    • Kafka tabanlı yapı izleme, arıza müdahalesi ve tuning gerektirir
    • Consumer gecikirse WAL dosyaları birikir → disk alanı yetersizliği riski oluşur
    • PostgreSQL 13+ içindeki max_slot_wal_keep_size ayarıyla bu sınırlandırılabilir
    • Replication slot gecikmesinin izlenmesi ve alarm üretilmesi şarttır
  • Avantajlar
    • Uygulama kodunu değiştirmeden tüm değişiklikler yakalanabilir
    • çeşitli hedeflere (S3, data warehouse, arama indeksi) stream edilebilir
    • Ana veritabanına ek yük bindirmez
  • Dezavantajlar
    • Operasyonel karmaşıklık ve altyapı maliyeti yüksektir
    • Consumer gecikirse veri kaybı veya yeniden senkronizasyon ihtiyacı doğabilir
    • Şema değişikliklerinde kaynak ile consumer arasında koordinasyon gerekir

Silmeleri işlemeyen bir replika fikri

  • DELETE sorgularını yok sayan bir PostgreSQL replikası tutma fikri öneriliyor
    • Silinmemiş tüm veriler kümülatif olarak saklanabilir
    • Arşiv verisi doğrudan sorgulanabilir
  • Olası sorunlar
    • Hangi verinin silindiğini ayırt etmek mümkün olmayabilir
    • Migration uygulanırken çakışma riski vardır
    • Depolama alanı ve operasyon maliyeti artar

Sonuç

  • Yeni projelerde trigger tabanlı arşivleme en pratik seçimdir
    • Kurulumu basittir ve canlı tabloları temiz tutar
    • Ek altyapı olmadan arşiv verisini sorgulamak ve yönetmek kolaydır
  • Karmaşık bir altyapı zaten mevcutsa veya birden çok hedefe streaming gerekiyorsa WAL tabanlı yaklaşım uygundur

4 yorum

 
love7peace 2026-01-23

Tetikleyici tabanlıysa veritabanına yük bindirdiğini öğrenmiştim...? Yine de tetikleyici öneriyor yani

 
nemorize 2026-01-24

O kadar trigger'ın oluşturduğu yük sorun oluyorsa, trigger olmasa bile zaten durum baştan aşağı sorun doludur.

 
cherrycoder 2026-01-23

Her zaman olduğu gibi, düzenlemeler bir maliyet. Gerçi sonuçta bunun bedelini ödemek yine tüketicilere düşecek.

 
GN⁺ 2026-01-23
Hacker News görüşleri
  • Çalıştığım bankacılık alanında aslında soft delete’in daha avantajlı olduğunu hissettim
    deleted_at sütunu olduğunda sorgu yazımı daha açık oluyor ve analiz sorguları ya da yönetici panelinde de aynı veri kümesiyle çalışılabiliyor
    Silme çoğu durumda nadir oluyor ve soft delete edilmiş satırların performans sorunu çıkardığına da neredeyse hiç rastlamadım
    Ayrıca ilişkiler aynen korunduğu için geri alma (undo) da kolay
    Hatta ben bir adım ileri gidip satırları tamamen değiştirilemez (immutable) yapmayı ve güncelleme gerektiğinde yeni satır eklemeyi tercih ediyorum
    Log tutmak gerekiyorsa DB trigger’larıyla INSERT/UPDATE/DELETE sırasında kopya bir tabloya kayıt bırakmanın iyi bir yaklaşım olduğunu düşünüyorum

    • Söylediğin doğru ama bunun yalnızca silmenin nadir olduğu durumlar için geçerli olduğunu düşünüyorum
      Gördüğüm tablolarda satırların %50~70’i soft delete edilmiş olduğunda performans düşüşü belirgindi
      Sonuçta soft delete duruma göre değişir ve ön analiz gerekir
    • Postgres’te yalnızca soft delete edilmemiş verileri indeksleyecek şekilde ayarlama da yapılabiliyor
      Çoğu durumda gerekmez ama RAM tasarrufu sağlayabilir
    • Bankacılıkta soft delete, denetlenebilirlik (auditability) eksikliğini geçici olarak örten bir çözümden ibaret
      Gerçek çözüm Event Sourcing; yani tüm değişikliklerin olay olarak kaydedilmesi gerekir
      Performans daha düşük olur ama snapshot ve senkronizasyon (sync) ile telafi edilebilir
    • DB’yi değiştirilemez bir yapıda işletmek için Datomic gibi sistemler düşünülebilir
      Time travel özelliğiyle geçmiş durumlar eksiksiz biçimde sorgulanabilir
    • Eskiden çalıştığım sigorta şirketinde de her tabloyu append-only log olarak işletiyorduk
      En güncel durum en büyük zaman damgasına sahip satırdaydı, geçmiş durumlar ise filtreyle sorgulanabiliyordu
      Bu yaklaşım güçlü bir geçmiş yönetimi sağlıyordu
  • Soft delete’in en büyük tuzağı sorgu karmaşıklığı
    Başta yalnızca WHERE deleted_at IS NULL eklemenin yeterli olduğu düşünülüyor ama birkaç ay sonra filtre eksikliği yüzünden hayalet veriler raporlarda görünmeye başlıyor
    View ile çözülebilir ama sonuçta paralel erişim desenlerini korumak gerekiyor ve silinmiş verileri sorgularken soyutlamayı aşmak gerekiyor
    Event sourcing daha temiz ama operasyon yükü yüksek olduğu için çoğu ekip hibrit yaklaşımı seçiyor

    • View yeterince güçlü bir araç
      Sorun, birçok SWE ve BI mühendisinin SQL ve şema tasarımına yeterince hâkim olmaması
      Soft delete’ten daha yaygın sorun ise Type 2 Slowly Changing Dimension işlemleri
      Çoğu kişi gereksiz yere audit table oluşturup verimsiz UPDATE/INSERT işlemlerini tekrarlıyor
      Aslında DB gerçekten çok güzel bir sistem ama o ölçüde hak ettiği saygıyı görmüyor olması üzücü
  • Soft delete’in DB yerleşik özelliği olarak sunulması iyi olurdu diye düşünüyorum
    Tablo bazında etkinleştirilebilse ve silme stratejisi seçilebilse ideal olurdu

    • Aslında Iceberg, Delta Lake, BigQuery gibi sistemler time travel özelliği sunuyor
      Ama birçok ekip özel gereksinimler nedeniyle sonunda SCD(Slowly Changing Dimension) yaklaşımıyla uyguluyor
  • Benim deneyimimde trigger tabanlı yaklaşım en istikrarlı olanıydı
    Arşiv tablosu append-only tutulmalı ve geri yükleme uygulama katmanında ele alınmalı
    Güncelleme soft delete gibi değerlendirilmeli ve trigger önceki durumu yakalamalı
    Trigger mutlaka BEFORE aşamasında çalışmalı ve mantık basit tutulmalı
    Partition’lar genelde aylık olur; yazma yükü fazlaysa günlük bölmek daha iyi olur

  • Ben DB’nin stateful → stateless yönünde evrilmesini istiyorum
    Tüm değişikliklerin append-only olaylar olarak kaydedildiği ve gerekli verinin view ile ifade edildiği yapıyı tercih ediyorum
    DB’nin materialized index’leri otomatik yönetmesi ideal olurdu
    Bazı modern DB’ler bunu sunuyor ama hâlâ OLTP odaklı gelişim yetersiz

  • Eskiden çalıştığım bir şirkette tüm sistemlerde soft delete uygulanıyordu
    Hocamın da “iş dünyasında veri asla silinmez” dediğini hatırlıyorum

    • Tam silme yapmak, gelecekteki veri analizi kabiliyetini kendi elinle sınırlamak demek
      Depolama ucuz olduğu için veriler asla silinmemeli
    • Ama düzeltmeler konusunda hocanın hiçbir şey söylememiş olması ilginç
  • Veritabanı olguların (fact) saklandığı yerdir
    Bir kaydın oluşturulması yeni bir olgudur, silinmesi de başka bir olgudur
    Ama satırı fiziksel olarak silersen olgu ortadan kaybolur
    Çoğu durumda bu tür silme istenmez

    • Ama veri sızıntı riski taşıyan bir varlıksa, tam tersine toplu silme gerekebilir
      Saklama maliyeti ve güvenlik riskleri hesaba katılmalı
    • DB değiştirilemez değilse, güncellemenin kendisi de zaten ortadan kaybolan bir olgu üretmiş olur
      Veriyi kalıcı olarak saklama kararı dikkatle verilmelidir
    • Kişisel olarak veri deposunun yalnızca okuma ve ekleme olmak üzere iki işlemi desteklemesi gerektiğini düşünüyorum
      Bunun için verinin yaşam döngüsünü anlamak önemlidir
  • Firezone başlangıçta soft delete’i denetim günlüğü için kullandı ama migration sorunları yüzünden vazgeçti
    Bunun yerine Postgres CDC(Change Data Capture) kullanarak olayları ayrı, yazma odaklı bir tabloya aktarma yaklaşımına geçti
    Soft delete, kullanıcı kurtarma özelliği için yararlı ama denetim veya regülasyon uyumluluğu için uygun değil diye düşünüyorum

    • Basit projelerde DB değişikliklerini denetlemek yerine doğrudan API çağrılarının denetlenmesi daha verimli olabilir
  • Soft delete alanı olan tabloların üstüne View oluşturup silinmiş satırları gizlemek temiz bir yaklaşım
    Böylece uygulamanın silinmiş olup olmadığını düşünmesine gerek kalmaz

    • Postgres’in RLS(Row Level Security) özelliğiyle soft delete edilmiş satırlar otomatik olarak gizlenebilir
      Uygulama yine aynı tablo üzerinde okuma/yazma/silme işlemlerini yapar
  • Şema kayması (schema drift) nasıl ele alınıyor diye soranlar var
    Silme anındaki şemaya göre serileştirilmiş veriyi daha sonra geri yüklemek istersen, şema değişiklikleri sorun yaratıyor

    • Benim deneyimimde arşivlenmiş nesnelere neredeyse hiç erişilmiyor
      Geri yükleme çoğunlukla silmeden sonraki birkaç gün içinde yapıldığı için şema değişikliklerinin etkisi sınırlı kalıyor
      Eski arşivleri yeni modele migrate etmek karmaşık ve hata olasılığı yüksek bir işti
      Sonuçta yaklaşım, sistemin nasıl kullanıldığına göre değişiyor