SQLProgramlamaPostgreSQL Geliştiricisi

Tek bir **DML** ifadesi tarafından değiştirilmiş tüm satırlar kümesine erişmek için **PostgreSQL** tetikleyicilerinin hangi mekanizma kullanılır ve bu mekanizma her satır için bir kez ateş etmeyecektir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Sorunun cevabı

Geçiş tabloları, PostgreSQL 10'da tanıtılmıştır ve bu yeteneği ifade düzeyindeki tetikleyicilerdeki REFERENCING ile sağlar. Bu mekanizma, bir değişikliğin tüm sonuç kümesini geçici tablo yapıları olarak açar—INSERT/UPDATE işlemleri için NEW TABLE ve DELETE/UPDATE işlemleri için OLD TABLE—bu sayede tetikleme fonksiyonu küme tabanlı işlem yapabilir. Satırları tek tek döngüye sokmak yerine, etkilenen tüm satırlar üzerinde aynı anda işlem yapan tek bir SQL ifadesi çalıştırabilirsiniz.

CREATE TRIGGER bulk_audit_trigger AFTER UPDATE ON inventory REFERENCING NEW TABLE AS updated_items OLD TABLE AS previous_items FOR EACH STATEMENT EXECUTE FUNCTION log_inventory_changes();

log_inventory_changes() içinde, updated_items sorgulamak, tetikleme UPDATE işleminden etkilenen tüm satırları döndürür; böylece INSERT INTO audit_log SELECT * FROM updated_items; gibi verimli toplu işlemler gerçekleştirilir.

Gerçek hayattan bir durum

Bir e-ticaret platformu, 100,000 ürün kaydını etkileyen gece toplu fiyat ayarlamaları sırasında ciddi performans düşüklüğü yaşadı. Mevcut mimari, denetim girişlerini yazmak için bir satır düzeyinde AFTER tetikleyici kullanıyordu, bu da price_history tablosuna 100,000 ardışık INSERT gerçekleştirilmesine neden oluyor ve bağlantı havuzu kaynaklarını tüketiyordu.

Çözüm 1: Uygulama tarafında toplu işleme Ekip, tetikleyiciyi kaldırmayı ve denetim işlemlerini Java uygulamasında JDBC toplu eklemeleri kullanarak yönetmeyi düşündü. Bu, veritabanı CPU yükünü azaltırdı, ancak kritik tutarlılık riskleri doğururdu: uygulama paket sırasında çökerse, taahhüt edilen fiyat güncellemeleri kalıcı olarak ilgili denetim kayıtlarından yoksun kalırdı, bu da SOX uyumluluğunu ihlal ederdi. Ayrıca, bu yaklaşım, uygulama sunucusu ile PostgreSQL arasında karmaşık dağıtılmış işlem yönetimini gerektiriyordu.

Çözüm 2: Asenkron mesaj kuyruğu Başka bir öneri, güncelleme sırasında satır tanıtıcılarını bir Redis akışına yazmak ve ardından arka planda çalışan bir işçi aracılığıyla denetim işlemlerini işlemekti. Bu, yazma yollarını birbirinden ayırdı ancak anında işlem tutarlılığını feda etti. Asenkron işçi, yüksek yük sırasında gecikebilir ve düzenleyici denetçilerin dikkatini çekecek denetim izinde geçici boşluklar oluşturabilirdi. Ayrıca, PostgreSQL ve Redis arasında tam bir kez anlamı sağlamak önemli altyapı karmaşıklığı ekledi.

Çözüm 3: Geçiş tabloları ile ifade düzeyinde tetikleyici Seçilen yaklaşım, satır tetikleyicisini REFERENCING NEW TABLE AS new_prices kullanan bir ifade düzeyinde tetikleyici ile değiştirdi. Tetikleyici fonksiyonu, tek bir küme tabanlı işlem gerçekleştirdi: INSERT INTO price_history SELECT product_id, old_price, new_price, NOW() FROM new_prices;. Bu, aynı işlem içinde katı ACID uyumluluğunu korudu ve tüm değişiklikleri tek seferde işledi.

Sonuç: Gece toplu iş tamamlama süresi 45 saniyeden 300 milisaniyeye düştü. WAL (Write-Ahead Log) üretimi %90 azaldı ve sistem, daha önce büyük tetikleyici rekursionu tarafından neden olunan kilit çatışması zirvelerini ortadan kaldırdı.

Adayların sıkça kaçırdığı noktalar

Geçiş tabloları BEFORE tetikleyicileri ve görünüm üzerindeki INSTEAD OF tetikleyicileri ile nasıl etkileşime girer?

Geçiş tabloları yalnızca sıradan tablolardaki AFTER tetikleyicilerde kullanılabilir. BEFORE tetikleyicileri, ifadenin nihai sonuç kümesi oluşmadan önce bireysel satırlar üzerinde çalışır, bu nedenle değiştirilmiş satırların tam koleksiyonu henüz mevcut değildir. Görünümler üzerindeki INSTEAD OF tetikleyicileri, gerçek DML işlemlerinin altındaki temel tablolardaki sonuçları gözlemlemek yerine alternatif yürütme yolları tanımladıkları için geçiş tablolarını kullanamazlar.

Tetikleyici fonksiyonu NEW TABLE veya OLD TABLE içindeki verileri değiştirip son sonucu değiştirebilir mi?

Hayır, geçiş tabloları yalnızca tetikleyici yürütülürken erişilebilen salt okunur anlık görüntülerdir. İfade tarafından etkilenen satırların değiştirilemeyen görüntülerini temsil ederler ve UPDATE, DELETE veya INSERT işlemleriyle değiştirilemezler. Değerleri taahhüt edilmeden önce değiştirmek için, NEW kayıt değişkenini doğrudan manipüle eden satır düzeyinde BEFORE tetikleyicileri kullanmalısınız veya kalıcı tablolara karşı ayrı DML gerçekleştirmeniz gerekir.

Neden TRUNCATE işlemleri OLD TABLE geçiş tablosunu doldurmaz?

PostgreSQL'ün TRUNCATE üzerine ifadeye dayalı tetikleyicileri desteklemesine rağmen, bu DDL komutu tüm satırları sona erdirir ve bireysel satır geçiş durumları oluşturmaz. TRUNCATE, geçiş ilişkilerini inşa etmek için kullanılan tuple versiyonlama mekanizmasını atlar, bu nedenle OLD TABLE'ın silinen satırlarla doldurulmasını sağlayamaz. TRUNCATE işlemlerinin denetimi, etkin tetikleyiciler veya mantıksal kodlama akışları gibi alternatif mekanizmalar gerektirir.