1 puan yazan GN⁺ 3 시간 전 | Henüz yorum yok. | WhatsApp'ta paylaş
  • Verinin belirli bir tarihteki (geçen salı) halinin ne olduğunu soran sorgulara yanıt verebilmek için Postgres 19, yerel zamansal geçmiş tablosu (temporal table) desteği getiriyor; böylece ayrı bir denetim tetikleyicisi sistemi olmadan değişiklik öncesi ve sonrası veriler izlenebiliyor
  • SQL:2011 standardının 10 yılı aşkın süre önce tanımladığı Temporal tablolar, Postgres tarafından ancak şimdi çekirdeğe alınıyor; böylece diğer veritabanı motorlarına kıyasla daha geç katılmış oluyor
  • Mevcut valid_from/valid_to iki sütunu ve btree_gist uzantısı tabanlı dışlama kısıtı (exclusion constraint) yerine, tek bir aralık türü (range type) sütunu ve WITHOUT OVERLAPS kısıtıyla daha sezgisel bir ifade sunuluyor
  • FOR PORTION OF sözdizimiyle UPDATE·DELETE sırasında satırlar otomatik bölünüyor, zaman eksenindeki boşluk ve çakışmalar motor tarafından ele alınıyor
  • Bu ekleme, iki zamanlı (bi-temporal) sistemlerin yalnızca geçerlilik zamanı (application time) yarısını kapsıyor; sistem zamanı (system time) henüz desteklenmese de ilerideki sürümler için temel atıyor

Mevcut yöntem - The Old-Fashioned Way

  • Ürün fiyatlarını zaman içinde izlemeye yönelik ilk yaklaşım, valid_from, valid_to adlı iki tarih sütunu ve valid_from < valid_to CHECK kısıtından oluşuyordu
    • Ancak aynı ürün için tarih aralığı çakışan iki satırın eklenmesini engelleyemiyordu (ör. ürün 42 aynı salı günü hem $9.99 hem de $14.99)
  • Geleneksel çözüm, btree_gist uzantısı ve dışlama kısıtı (exclusion constraint) kullanmaktı
    • EXCLUDE USING gist (product_id WITH =, daterange(valid_from, valid_to) WITH &&) biçimiyle çakışan satır eklenince hata veriliyordu
  • Bu yaklaşımın sorunları
    • GiST, Postgres'e özgü bir indeksleme yapısı olduğundan deneyim gerektiriyor ve isteğe bağlı bir uzantı olması giriş bariyeri yaratıyor
    • Dışlama kısıtı sözdizimi sezgisel değil; standart bir yaklaşım olarak akla gelmesi zor
    • Tabloya zaman farkındalığı gömülü değil; zaman aralıkları değiştiğinde satırları elle bölmek ve birleştirmek gerekiyor, zamansal tutarlılık yükü uygulamaya aktarılıyor

Zamanın kısa tarihi - A Brief History of Time

  • SQL:2011 standardı, geçerlilik zamanı dönemini (APPLICATION TIME), WITHOUT OVERLAPS kısıtını ve zamansal veri işleme için FOR PORTION OF sözdizimini tanımladı
  • Henrietta Dombrovskaya (Hetti), Chad Slaughter ile birlikte pg_bitemporal uzantısını geliştirdi; bu, Postgres içinde PL/pgSQL ile iki zamanlı tabloları yöneten bir çerçeve
    • 2015'ten bu yana çeşitli konferanslarda kavramı anlattı; **geçerlilik zamanı (valid time)**nı (gerçek dünyada bir bilginin doğru olduğu an) ve **işlem zamanı (transaction time)**nı (veritabanının bu bilgiyi kaydettiği an) aynı anda izlemeyi gösterdi
  • İki zaman boyutunun farkı
    • Geçerlilik zamanı, "bu fiyat ocaktan hazirana kadar geçerli" anlamına geliyor
    • İşlem zamanı ise veritabanı açısından "bu satır 12 Mart saat 15:47'de eklendi, 3 Nisan saat 09:01'de değiştirildi" demek
    • İkisi birleştirildiğinde, "o zaman bildiğimiz bilgiye göre geçen salı fiyatın ne olduğunu düşünüyorduk" sorusuna yanıt veren iki zamanlı tablolar kurulabiliyor
  • pg_bitemporal, EXCLUDE USING gist ifadesini iki kez kullanıyor; biri effective aralığına (geçerlilik zamanı), diğeri asserted aralığına (işlem zamanı) uygulanıyor
    • İki zamanlı ekleme, güncelleme, düzeltme, devre dışı bırakma ve silme işlevleri ile zamansal çıkarım için Allen'ın aralık ilişkileri (Allen's interval relationships) desteği sunuyor
  • Uzantının sınırları
    • Sorgu planlayıcısını zamansal koşulları tanıyacak şekilde değiştiremiyor, motor düzeyindeki kısıt sistemiyle bütünleşemiyor, yerel veri işleme sözdizimi sağlayamıyor → çekirdeğe girmesi gerekiyordu
    • Postgres 19, iki zamanlı sistemlerin geçerlilik zamanı yarısını benimsiyor; tam çözüm değil ama büyük bir ilerleme

Aralıklar imdada yetişiyor - Ranges to the Rescue

  • Postgres 19 yaklaşımı, ayrı valid_from/valid_to yerine tek bir aralık türü sütunu olan valid_at DATERANGE kullanıyor
    • PRIMARY KEY (product_id, valid_at WITHOUT OVERLAPS) ile btree_gist uzantısı ve dışlama kısıtı gerekmiyor
    • WITHOUT OVERLAPS, product_id değerinin herhangi bir anda benzersiz olmasını sağlıyor; ama aralıklar çakışmadığı sürece aynı ürün için birden fazla satıra izin veriyor
  • İçeride hâlâ GiST indeksi kullanılıyor ve anahtarın zamansal olmayan sütunları için btree_gist gerekiyor; ancak kısıt oluşturulurken bağımlılıklar Postgres tarafından otomatik yönetiliyor
  • Aralık gösteriminde [ dahil, ) hariç anlamına geliyor → [2025-01-01, 2025-07-01) 1 Ocak'ı kapsıyor, 1 Temmuz'u kapsamıyor
    • Son Gadget satırı [2026-01-01,), bitiş tarihi olmayan açık uçlu (open-ended) bir aralık; yani mevcut fiyat için tanımlı bir bitiş yok
  • Çakışma korumasının davranışı
    • Hatalı [2025-03-01, 2025-01-01) aralığı eklenirse "aralığın alt sınırı üst sınırdan küçük veya ona eşit olmalı" hatası veriliyor
    • Çakışan [2025-03-01, 2025-09-01) aralığı eklenirse products_pkey dışlama kısıtı ihlali oluşuyor
    • Yalnızca aralık türü kullanarak iki tür doğrulama birden elde ediliyor

Kesip biçmek - Slicing and Dicing

  • Bir ürünün fiyatını yalnızca 2025 Mart–Eylül arasında $10.99 yapmak istenirse, eski yöntemde satırları elle bölmek ve eklemek gerekiyordu; bu da hata halinde boşluk ve çakışmalar doğurabiliyordu
  • Zamansal geçmiş tablosunda bu, niyet edildiği gibi doğrudan ifade edilebiliyor
    • UPDATE products FOR PORTION OF valid_at FROM '2025-03-01' TO '2025-09-01' SET price = 10.99 WHERE product_id = 1
  • Sonuç olarak Widget satırları 3'ten 5'e çıkıyor
    • Mevcut $9.99 satırı [2025-01-01, 2025-03-01) aralığına küçülüyor
    • Kalan aralık için yeni bir $10.99 satırı ekleniyor
    • Mevcut $12.99 satırı [2025-09-01, 2026-01-01) aralığına küçülüyor
    • Kalan [2025-07-01, 2025-09-01) aralığı için yeni bir $10.99 satırı daha ekleniyor
  • $10.99'ın iki satıra bölünmesinin nedeni, FOR PORTION OF ifadesinin eşleşen her satırı bağımsız işlemesi ve bitişik aralıkları sonradan birleştirmemesi (coalesce)
    • Nihai sonuçta boşluk ya da çakışma yok; bu da salt dışlama mantığının (exclusion logic) sunmadığı bir avantaj
  • Sınır durumlar (edge case)
    • FOR PORTION OF aralığı mevcut tek bir satırın tamamen içindeyse, en fazla 2 artık satır (ön ve arka) oluşabiliyor
    • Mevcut sınırlarla tam çakışıyorsa artık satır gerekmiyor
  • Yeni oluşan zamansal artık satırlar için INSERT izni gerekmiyor, ancak mevcut INSERT tetikleyicileri yine çalışıyor → denetim kaydı veya SECURITY DEFINER tetikleyici işlevlerinde buna dikkat etmek gerekiyor

Geçmişi silmek - Erasing History

  • FOR PORTION OF, DELETE için de çalışıyor; örneğin belirli bir ürünü 2025 Haziran–Ekim arasında katalogdan geçici olarak kaldırmak mümkün
    • DELETE FROM products FOR PORTION OF valid_at FROM '2025-06-01' TO '2025-10-01' WHERE product_id = 2
  • Sonuç
    • Haziran–Ekim aralığı kesilip çıkarılıyor ve [2025-04-01, 2026-01-01) aralığını kaplayan $22.99 satırı, haziranda biten bir satır ile ekimde başlayan iki artık satıra bölünüyor
    • Boşluğun öncesi ve sonrasındaki fiyat verisi özgün değerleriyle korunuyor; yani DELETE, satır sayısını artırabiliyor
  • Zamansal geçmiş tablosu yönetim mekanizması bunların hepsini otomatik yapıyor; böylece uygulama düzeyinde aşırı silme veya sahipsiz parça (orphaned fragment) riski ortadan kalkıyor

Reklamdaki doğruluk - Truth in Advertising

  • Zamansal geçmiş tabloları, zamansal dış anahtarlar (temporal foreign key) olmadan tamamlanmış sayılmaz; Postgres 19 bunu PERIOD anahtar sözcüğüyle destekliyor
    • FOREIGN KEY (product_id, PERIOD valid_at) REFERENCES products (product_id, PERIOD valid_at) biçiminde tanımlanıyor
  • PERIOD anahtar sözcüğü, dış anahtarın kendisinin zamansal tabanlı olduğunu belirtiyor
    • Başvurulan product kaydı, variant'ın valid_at aralığının tamamı boyunca mevcut olmalı
    • Başvurulan tablodaki tüm eşleşen satırların birleşimi, başvuran satırın zaman aralığını tamamen kapsamalı
  • product zaman aralığını aşan bir variant oluşturma girişimi ([2025-01-01, 2027-01-01)) reddediliyor
    • Widget fiyatı yalnızca 2026 ortasına kadar tanımlıyken 2027'ye kadar geçerli olduğunu iddia eden bir variant, dış anahtar kısıtı ihlaliyle engelleniyor
  • Önemli bir sınırlama var
    • Zamansal dış anahtarlar, başvuru eylemi (referential action) olarak yalnızca NO ACTION destekliyor; CASCADE, SET NULL ve SET DEFAULT yok
    • Variant'ın bağlı olduğu product satırı silinirse her zaman hata oluşuyor; bunun nedeni zincirleme zamansal işlemlerin karmaşıklığı ve bunun uygulama tarafından açıkça ele alınması gereği

Küçük adımlar - Baby Steps

  • Şu anda gelen yetenekler: çakışmayı önleyen geçerlilik zamanı tabanlı zamansal geçmiş tabloları, zamansal veri işleme ve zamansal dış anahtarlar
  • En büyük eksik, işlem zamanı olarak da bilinen sistem zamanı (system time)
    • Geçerlilik zamanı, bir olgunun gerçek dünyada ne zaman doğru olduğunu izler; sistem zamanı ise veritabanının bu olgudan ne zaman haberdar olduğunu izler; birçok sistem her ikisini de kullanır
    • Bu alanı 2015'ten beri pg_bitemporal uzantısı dolduruyordu
    • Tetikleyicilerle sistem zamanını taklit etmek mümkün, ancak bu; diğer yeni zamansal özelliklerde olduğu gibi motorun şeffaf biçimde yönetmesiyle aynı şey değil
  • Zamansal geçmiş tablosu belgeleri de sistem zamanının yerel olarak desteklenmediğini, ama taklit edilebildiğini açıkça belirtiyor; Postgres 20 ve sonrası için eklenip eklenmeyeceği belirsiz olsa da temel şimdiden atılmış durumda

Son düşünceler - Final Thoughts

  • EXCLUDE USING gist yaklaşımı çalışıyor ama görece kaba bir geçici çözüm; pg_bitemporal gibi uzantılar kavramı kanıtlayıp tartışmayı bugüne taşıdı
  • GiST dışlama kısıtlarına göre çok daha sezgisel bir yaklaşım
    • Birincil anahtardaki WITHOUT OVERLAPS sıradan bir İngilizce ifade gibi okunuyor, FOR PORTION OF ise yaptığı işi doğrudan anlatıyor
    • Zamansal güncelleme ve silmelerde otomatik satır bölme, potansiyel hata sınıflarından birini ortadan kaldırıyor
  • SQL:2011'den Postgres 19'a uzanan yol uzun oldu; Hetti ve topluluk yıllar boyunca bu desenin gerekliliğini ve uygulanabilirliğini gösterdi, şimdi de çekirdeğe girmiş oldu
  • Gelecek sürümlerde sistem zamanı desteğini izlemek gerekecek; Postgres iki zamanlı yapının her iki yarısını da tamamladığında olasılıklar ciddi biçimde genişleyecek

Henüz yorum yok.

Henüz yorum yok.