GÜNCELLEME İÇİN SEÇ… ne zaman kullanılır?


119

Lütfen arkasındaki kullanım durumunu anlamama yardım edin SELECT ... FOR UPDATE.

Soru 1 : Aşağıdaki, ne zaman SELECT ... FOR UPDATEkullanılması gerektiğine dair iyi bir örnek mi?

Verilen:

  • Odalar [kimlik]
  • etiketler [id, name]
  • room_tags [room_id, tag_id]
    • room_id ve tag_id yabancı anahtarlardır

Uygulama tüm odaları ve etiketlerini listelemek istiyor, ancak etiketsiz odalar ile kaldırılmış odalar arasında ayrım yapması gerekiyor. SELECT ... FOR UPDATE kullanılmazsa, ne olabilir:

  • Başlangıçta:
    • odalar içerir [id = 1]
    • etiketler içerir [id = 1, name = 'cats']
    • room_tags şunu içerir: [room_id = 1, tag_id = 1]
  • Konu 1: SELECT id FROM rooms;
    • returns [id = 1]
  • Konu 2: DELETE FROM room_tags WHERE room_id = 1;
  • Konu 2: DELETE FROM rooms WHERE id = 1;
  • Konu 2: [işlemi gerçekleştirir]
  • Konu 1: SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
    • boş bir liste döndürür

Şimdi Konu 1, oda 1'de etiket olmadığını düşünüyor, ancak gerçekte oda kaldırıldı. Bu sorunu çözmek için, İplik 1 SELECT id FROM rooms FOR UPDATE, İplik 2'nin rooms1. İplik tamamlanana kadar silinmesini engellemelidir . Bu doğru mu?

Soru 2 : Ne zaman bir kullanmalıdır SERIALIZABLEişlem yalıtım karşı READ_COMMITTEDolan SELECT ... FOR UPDATE?

Cevapların taşınabilir olması beklenir (veritabanına özgü değil). Bu mümkün değilse lütfen nedenini açıklayın.


2
Hangi RDBMS'yi kullanıyorsunuz?
Quassnoi

2
@Quassnoi, sorunun altında belirtildiği gibi, taşınabilir (veritabanına özgü değil) bir çözüm arıyorum.
Gili

2
Seçenekler REPEATABLE_READve READ_COMMITTEDhatta taşınabilir seçenekler mi? Bunlar için aldığım tek sonuç MSSQL sunucusu için
Billy ONeal

3
@BillyONeal: İzolasyon modlarının izin vermedikleri tuhaflıkları görmemenizi garanti ettiğini, ancak izin verdikleri tuhaflıklar hakkında hiçbir şey söylemediğini unutmayın. Bu, READ COMMITTEDmod ayarının, başka bir işlem tarafından işlenen kayıtları gerçekten görüp görmeyeceğinizi tanımlamadığı anlamına gelir : yalnızca, kaydedilmemiş kayıtları asla görmeyeceğinizden emin olur.
Quassnoi

3
A select ... for updateon , ayrı tablolar oldukları için silinmeye roomsyine de izin verecektir room_tags. for updateMaddenin silinmeleri engelleyip engellemeyeceğini roomsmi sormak istediniz ?
Chris Saxon

Yanıtlar:


84

Odalar ve etiketler arasında tutarlılık sağlamanın ve odaların silindikten sonra asla iade edilmemesini sağlamanın tek taşınabilir yolu onları kilitlemektir SELECT FOR UPDATE.

Ancak bazı sistemlerde kilitleme, eşzamanlılık kontrolünün bir yan etkisidir ve siz aynı sonuçları FOR UPDATEaçıkça belirtmeden elde edersiniz .


Bu sorunu çözmek için, İplik 1 SELECT id FROM rooms FOR UPDATE, İplik 2'nin rooms1. İplik tamamlanana kadar silinmesini engellemelidir . Bu doğru mu?

Bu, veritabanı sisteminizin kullandığı eşzamanlılık kontrolüne bağlıdır.

  • MyISAMin MySQL(ve diğer birkaç eski sistemde) bir sorgu süresince tüm tabloyu kilitler.

  • İçinde SQL Server, SELECTsorgular inceledikleri kayıtlara / sayfalara / tablolara paylaşılan kilitler yerleştirirken, DMLsorgular güncelleme kilitleri yerleştirir (daha sonra özel kilitlere yükseltilir veya paylaşılan kilitlere indirgenir). Özel kilitler, paylaşılan kilitlerle uyumlu değildir, bu nedenle başka bir oturum tamamlanana kadar ya ya SELECTda DELETEsorgu kilitlenir.

  • Veritabanları içinde hangi kullanım MVCC(gibi Oracle, PostgreSQL, MySQLile InnoDB), bir DMLsorgu (bir veya başka şekilde) kaydının bir kopyasını oluşturur ve genellikle okuyucular tersi yazarları ve yardımcısı blok yok. Bu veritabanları için a SELECT FOR UPDATEkullanışlı olacaktır: tıpkı başka bir oturum tamamlanana kadar ya SELECTya da DELETEsorguyu kilitleyecektir SQL Server.

Ne zaman bir kullanmalıdır REPEATABLE_READkarşı hareket yalıtım READ_COMMITTEDile SELECT ... FOR UPDATE?

Genel olarak, REPEATABLE READhayali satırları (değiştirilmek yerine başka bir işlemde görünen veya kaybolan satırlar) yasaklamaz

  • Gelen Oracleve önceki PostgreSQLsürümleri, REPEATABLE READaslında eşanlamlıdır SERIALIZABLE. Temel olarak bu, işlemin başladıktan sonra yapılan değişiklikleri görmediği anlamına gelir. Dolayısıyla bu kurulumda, son Thread 1sorgu odayı hiç silinmemiş gibi geri döndürecektir (ki bu istediğiniz şey olabilir veya olmayabilir). Odaları silindikten sonra göstermek istemiyorsanız, satırları ile kilitlemelisiniz.SELECT FOR UPDATE

  • İse InnoDB, REPEATABLE READve SERIALIZABLEfarklı şeylerdir: in okuyucular SERIALIZABLEetkin bir birlikte yapılan önlenmesi onlar değerlendirmek kayıtlarına modu seti sonraki anahtar kilitler, DMLüzerlerinde. Yani SELECT FOR UPDATEserileştirilebilir modda a'ya ihtiyacınız yok, ancak REPEATABLE READveya READ COMMITED.

İzolasyon modları ile ilgili standardın, sorgularınızda belirli tuhaflıkları görmediğinizi, ancak nasıl olduğunu (kilitleyerek veya ile MVCCveya başka türlü) tanımlamadığına dikkat edin .

"İhtiyacınız yok SELECT FOR UPDATE" dediğimde, belirli veritabanı motoru uygulamalarının yan etkileri nedeniyle "gerçekten eklemeliydim".


1
Son nokta, konunun özü, sanırım: "serileştirilebilir modda GÜNCELLEME İÇİN SEÇİM'e ihtiyacınız yok, ancak TEKRARLANABİLİR OKUMA veya TAMAMLANAN OKUMA modunda bunlara ihtiyacınız var".
Colin 't Hart

Haklısın. İkinci soru sormalıydık SERIALIZABLEkarşı kullanılmalıdır READ_COMMITTEDile SELECT ... FOR UPDATE. Lütfen yanıtınızı bu güncellenmiş soruyu yansıtacak şekilde günceller misiniz?
Gili

1
@Gili: " SELECT FOR UPDATEserileştirilebilir kipte ihtiyacınız yok ", ile InnoDB. Diğer MVCCsistemlerle, ikisi eşanlamlıdır ve ihtiyacınız vardır SELECT FOR UPDATE.
Quassnoi

1
Colin'in gönderisinin özel sorularımı yanıtınızdan daha iyi yanıtladığını görüyorum, ancak verdiğiniz tüm referansları takdir ediyorum. İkisini en iyi şekilde birleştiren bir cevabı kabul edeceğim (belirli cevaplar üstte, aşağıdaki referansları destekler).
Gili

This depends on the concurrency control your database system is using: Sanırım saçları bölüyorsunuz. Aşağıda listelediğiniz tüm vakalar SELECT, işlemin sonuna kadar odanın silinmediğini söylüyor . Öyleyse, cevap sadece Yesaşağıdaki destekleyici referanslarla olmamalı mı?
Gili

33

Kısa cevaplar:

S1: Evet.

S2: Hangisini kullandığınız önemli değil.

Uzun cevap:

Bir select ... for updateirade (ima ettiği gibi) belirli satırları seçer, ancak aynı zamanda bunları mevcut işlem tarafından önceden güncellenmiş gibi (veya kimlik güncellemesi yapılmış gibi) kilitler. Bu, bunları geçerli işlemde yeniden güncellemenize ve ardından başka bir işlemin bu satırları herhangi bir şekilde değiştirmesine gerek kalmadan gerçekleştirmenize olanak tanır .

Başka bir bakış açısı, aşağıdaki iki ifade atomik olarak yürütülüyor gibidir:

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;

Etkilenen satırlar my_conditionkilitlendiğinden, başka hiçbir işlem onları hiçbir şekilde değiştiremez ve bu nedenle işlem izolasyon seviyesi burada bir fark yaratmaz.

İşlem yalıtım düzeyinin kilitlemeden bağımsız olduğunu da unutmayın: Farklı bir yalıtım düzeyi ayarlamak, işleminiz tarafından kilitlenen farklı bir işlemdeki satırları kilitlemenize ve güncellemenize izin vermez.

İşlem izolasyon seviyelerinin (farklı seviyelerde) garanti ettiği, işlemler devam ederken verilerin tutarlılığıdır.


1
Sanırım What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.yanlış bir şekilde izolasyon seviyelerinin bir işlem sırasında olanları etkilemediğini ima ediyor . Bu bölümü gözden geçirmenizi ve işlem sırasında gördüklerinizi (veya görmediklerinizi) nasıl etkiledikleri hakkında daha fazla ayrıntı sağlamanızı öneririm.
Gili

1
Gönderinizin özel sorularımı Quassnoi'den daha iyi yanıtladığını görüyorum, ancak sağladığı tüm referansları takdir ediyorum. İkisini en iyi şekilde birleştiren bir cevabı kabul edeceğim (belirli cevaplar üstte, aşağıdaki referansları destekler).
Gili

Kilitleme ve izolasyon birbirinin yerine geçecek şekilde karmaşıktır. Peki bu konuda bilgi alabileceğiniz kitap var mı?
Chao
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.