Mat ve Erwin her ikisi de haklıdır ve sadece bir yoruma uymayacak şekilde söylediklerini daha da genişletmek için başka bir cevap ekliyorum. Verdikleri cevaplar herkesi tatmin etmiyor gibi görünüyor ve PostgreSQL geliştiricilerine danışılması gereken bir öneri vardı ve ben bir tane olacağım.
Buradaki önemli nokta, SQL standardı altında, READ COMMITTED
işlem izolasyon düzeyinde çalışan bir işlem içinde , kısıtlamanın, tamamlanmamış işlemlerin çalışmasının görünmemesi gerektiğidir. Ne zaman işlenen işlemlerin çalışma görünür hale uygulama bağlıdır. Dikkatinizi çektiğiniz şey, iki ürünün bu uygulamayı nasıl seçtiğindeki fark. Her iki uygulama da standardın gereklerini ihlal etmemektedir.
İşte PostgreSQL'in içinde detaylı olarak olanlar:
S1-1 çalışır (1 satır silindi)
Eski satır yerinde kalır, çünkü S1 hala geri dönebilir, ancak S1 şimdi satır üzerinde bir kilit tutar, böylece satırı değiştirmeyi deneyen herhangi bir oturum S1'in tamamlanıp geri alınmayacağını görmek için bekler. Tablonun herhangi bir okunu , SELECT FOR UPDATE
ya da ile kilitlemeye çalışmadıkça eski satırı görebilir SELECT FOR SHARE
.
S2-1 çalışıyor (ancak S1'in yazma kilidi olduğu için engellendi)
S2 şimdi S1'in sonucunu görmek için beklemek zorunda. S1 yerine taahhüt geri almak olsaydı, S2 satırı silerdi. S1, geri dönmeden önce yeni bir sürüm eklerse, yeni sürümün hiçbir zaman başka bir işlemin perspektifinde bulunmadığını, eski sürümün de başka bir işlemin perspektifinden silinmeyeceğini unutmayın.
S1-2 çalışır (1 satır eklendi)
Bu satır eskisinden bağımsızdır. Satır kimliği = 1 olan bir güncelleme olsaydı, eski ve yeni sürümler ilişkilendirilirdi ve S2, engellendiğinde satırın güncellenmiş sürümünü silebilirdi. Yeni bir satırın geçmişte varolan bazı satırlarla aynı değerlere sahip olması, o satırın güncellenmiş bir sürümüyle aynı olmasını sağlamaz.
S1-3 çalışır, yazma kilidini açar
Böylece S1'in değişiklikleri devam etti. Bir satır gitti. Bir satır eklendi.
S2-1 çalışır, şimdi kilidi alabilir. Ancak 0 satır silindi. BU NE ???
Dahili olarak gerçekleşen şey, bir satırın bir sürümünden, aynı satırın bir sonraki sürümüne güncellendiğinde bir işaretçi olduğudur. Satır silinirse, bir sonraki sürüm yoktur. Bir READ COMMITTED
işlem, bir yazma çatışması üzerindeki bir bloktan uyandığında, bu güncelleme zincirini sonuna kadar takip eder; Satır silinmediyse ve hala sorgunun seçim kriterlerine uyuyorsa işleme alınacaktır. Bu satır silindi, S2'nin sorgusu devam ediyor.
S2, tablo taraması sırasında yeni satıra geçebilir veya gelmeyebilir. Eğer öyleyse, S2'nin DELETE
ifadesi başladıktan sonra yeni satırın yaratıldığını görecek ve bu nedenle de görülebilir satır kümesinin bir parçası değildir.
PostgreSQL S2'nin tüm DELETE deyimini yeni bir anlık görüntü ile baştan başlatırsa, SQL Server ile aynı şekilde davranırdı. PostgreSQL topluluğu, performans nedenleriyle bunu yapmayı seçmedi. Bu basit durumda, performans farkını asla farketmezsiniz, ancak DELETE
bloke olduğunuzda on milyon sıra olsaydınız, kesinlikle anlarsınız. Burada PostgreSQL'in performans seçtiği takas var, çünkü daha hızlı sürüm hala standardın şartlarına uyuyor.
S2-2 çalışır, benzersiz bir anahtar kısıtlama ihlali bildirir
Tabii ki, sıra zaten var. Bu, resmin en az şaşırtıcı kısmı.
Burada bazı şaşırtıcı davranışlar olsa da, her şey SQL standardına uygun ve standarda göre "uygulamaya özgü" sınırlar dahilinde. Diğer uygulamaların davranışlarının tüm uygulamalarda mevcut olacağını varsayıyorsanız, kesinlikle şaşırtıcı olabilir, ancak PostgreSQL, READ COMMITTED
yalıtım düzeyindeki serileştirme hatalarını önlemek için çok çaba sarf eder ve bunu başarmak için diğer ürünlerden farklı bazı davranışlara izin verir.
Şimdi, şahsen ben herhangi bir ürünün uygulamasında READ COMMITTED
işlem izolasyon seviyesinin büyük bir hayranı değilim . Hepsi yarış koşullarının işlemsel açıdan şaşırtıcı davranışlar yaratmasına izin veriyor. Birisi bir ürünün izin verdiği garip davranışlara alıştığında, “normal” ve başka bir ürünün seçtiği takasların tuhaf olduğunu düşünmeye meyillidirler. Ancak her ürün, aslında uygulanmayan herhangi bir mod için bir çeşit takas yapmak zorundadır . PostgreSQL geliştiricilerinin çizgiyi çizmeyi seçtikleri yerde engellemeyi en aza indirmek (okuma yazmalarını engellemiyor ve yazma okumaları engellemiyor) ve seri hale getirme başarısızlıklarını en aza indirmektir.SERIALIZABLE
READ COMMITTED
Standart, SERIALIZABLE
işlemlerin varsayılan olmasını gerektirir , ancak çoğu ürün bunu yapmaz, çünkü daha gevşek işlem yalıtım düzeylerinde bir performansa neden olur. Bazı ürünler SERIALIZABLE
seçildiğinde bile gerçekten seri hale getirilebilir işlemler sağlamamaktadır - özellikle de Oracle ve 9.1'den önceki PostgreSQL sürümleri. Ancak gerçek SERIALIZABLE
işlemlerin kullanılması, yarış koşullarından şaşırtıcı etkilerden kaçınmanın tek yoludur ve yarış koşullarından SERIALIZABLE
kaçınmak için işlemler her zaman engellemeli veya gelişen bir yarış koşulunu önlemek için bazı işlemleri geri almalıdır. SERIALIZABLE
İşlemlerin en yaygın şekilde uygulanması , hem engelleme hem de serileştirme başarısızlıklarına sahip (kilitlenme şeklinde) Sıkı İki Fazlı Kilitleme'dir (S2PL).
Tam açıklama: Serializable Snapshot Isolation adlı yeni bir teknik kullanarak PostgreSQL sürüm 9.1'e gerçekten seri hale getirilebilir işlemler eklemek için Dan Port of MIT ile çalıştım.