Satır Kilidi İçeriklerini izleme, hata ayıklama ve düzeltme


12

Geç saatlerde, çok sayıda satır kilidi içeriğiyle karşılaştım. Çekişmeli tablo belirli bir tablo gibi görünüyor.

Genellikle olan budur -

  • Geliştirici 1, Oracle Forms kullanıcı arabirimi ekranından bir işlem başlatır
  • Geliştirici 2, aynı ekranı kullanan farklı bir oturumdan başka bir işlem başlatır

~ 5 dakika içinde, ön uç yanıt vermiyor gibi görünüyor. Oturumları kontrol etmek satır kilidi çekişmesini gösterir. Herkesin attığı "çözüm" oturumları öldürmektir: /

Veritabanı geliştiricisi olarak

  • Sıra kilidi içeriklerini ortadan kaldırmak için ne yapılabilir?
  • Saklı yordamın hangi satırının bu satır kilidi içeriklerine neden olduğunu bulmak mümkün müdür?
  • Kodlama gibi bu tür sorunları azaltmak / önlemek / ortadan kaldırmak için genel kılavuz nedir?

Bu soru çok açık uçlu / yetersiz bilgi veriyorsa lütfen düzenlemek / bildirmekten çekinmeyin - bazı ek bilgiler eklemek için elimden geleni yapacağım.


Söz konusu tablo çok fazla ek ve güncelleme altında, en yoğun tablolardan biri olduğunu söyleyebilirim. SP oldukça karmaşıktır - basitleştirmek için - çeşitli tablolardan veri alır, çalışma tablolarına doldurur, çalışma masasında çok sayıda aritmetik işlem gerçekleşir ve çalışma tablosunun sonucu söz konusu tabloya eklenir / güncellenir.


Veritabanı sürümü Oracle Database 10g Enterprise Edition Sürüm 10.2.0.1.0 - 64bit'tir. Mantık akışı her iki oturumda da aynı sırayla yürütülür, işlem çok uzun süre açık tutulmaz (veya en azından öyle düşünüyorum ) ve kilitler işlemlerin aktif yürütülmesi sırasında gerçekleşir.


Güncelleme: Tablo satırı sayısı yaklaşık 3,1 milyon satırda beklediğimden daha fazla. Ayrıca, bir oturumu izledikten sonra bu tablodaki güncelleme deyimlerinin birkaçının dizini kullanmadığını gördüm. Neden böyle - emin değilim. Where yan tümcesinde başvurulan sütun dizine eklenir. Şu anda dizini yeniden oluşturuyorum.


1
@Sathya - saklı yordamın karmaşıklığını ayrıntılı olarak açıklayabilir misiniz? şüpheli tablo sıkı güncelleme veya ekleme altında mı?
CoderHawk

Yabancı anahtarlar burada bir rol oynar mı? (Bazen bunun bir dizine ihtiyacı vardır) Hangi veritabanı sürümü mevcut? Mantık akışı her iki oturumda da aynı sırada mı yürütülüyor? İşlem uzun süre açık kalıyor mu? Kilit, kullanıcıların zamanı düşündüğü veya işlemin aktif yürütülmesi sırasında mı gerçekleşir?
ik_zelf

@Sandy Soruyu güncelledim
Sathyajith Bhat

@ik_zelf Soruyu güncelledim
Sathyajith Bhat

1
Bunun neden bir sorun olduğu açık değil - Oracle tam olarak yapması gereken şeyi yapıyor, ki bu da tek bir satıra erişimi seri hale getiriyor. Birisi bu satıra sahipse, önceki sürümünü okuyabilirsiniz, ancak yazmak için kilidi serbest bırakmasını beklemeniz gerekir. Bunun için tek "düzeltme" ya a) kandırmamak COMMITya da ROLLBACKmakul bir zamanda ya da b) aynı kişilerin aynı anda her zaman aynı sırayı istemeyecek şekilde düzenlenmesi.
Gaius

Yanıtlar:


10

Saklı yordamın hangi satırının bu satır kilidi içeriklerine neden olduğunu bulmak mümkün müdür?

Tam olarak değil ama kilit neden SQL deyimi alabilirsiniz ve sırayla yordamda ilgili satırları tanımlamak.

SELECT sid, sql_text
FROM v$session s
LEFT JOIN v$sql q ON q.sql_id=s.sql_id
WHERE state = 'WAITING' AND wait_class != 'Idle'
AND event = 'enq: TX - row lock contention';

Kodlama ile ilgili bu tür sorunları azaltmak / önlemek / ortadan kaldırmak için genel kılavuz nedir?

Kilitleri üzerinde Oracle Kavramlar Kılavuzu bölüm "bir yazar tarafından modifiye zaman bir satır sadece kilitli." Diyor Aynı satırı güncelleyen başka bir oturum ilk oturumun devam etmeden önce COMMITveya ROLLBACKdevam etmesini bekler . Sorunu ortadan kaldırmak için kullanıcıları serileştirebilirsiniz, ancak sorunu belki de sorun olmayacak seviyeye indirgeyebilecek bazı şeyler.

  • COMMITdaha sıklıkla. Her COMMITsürüm kilitlenir, bu nedenle güncellemeleri toplu olarak yapabiliyorsanız, aynı satıra ihtiyaç duyan başka bir oturumun olasılığı azalır.
  • Değerlerini değiştirmeden hiçbir satırı güncellemediğinizden emin olun. Örneğin UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);, daha seçici olarak yeniden yazılmalıdır (daha az kilit okuyun) UPDATE t1 SET f1=f1+1 WHERE f2=’a’;. Tabii ki, eğer değişiklik tablodaki satırların çoğunu hala kilitleyecekse, değişiklik sadece okunabilirlik avantajına sahip olacaktır.
  • En yüksek akım değerine bir tablo eklemek için tabloyu kilitlemek yerine sekans kullandığınızdan emin olun.
  • Bir dizinin kullanılmamasına neden olan bir işlev kullanmadığınızdan emin olun. İşlev gerekiyorsa, işlev tabanlı bir dizin yapmayı düşünün.
  • Kümeler halinde düşünün. Güncelleştirmeleri yapan bir PL / SQL bloğunu çalıştıran bir döngünün tek bir güncelleme ifadesi olarak yeniden yazılabilir olup olmadığını düşünün. Değilse, belki toplu işleme ile kullanılabilir BULK COLLECT ... FORALL.
  • İlk UPDATEile arasında yapılan işi azaltın COMMIT. Örneğin, kod her güncellemeden sonra bir e-posta gönderirse, e-postaları sıraya almayı ve güncellemeleri gerçekleştirdikten sonra göndermeyi düşünün.
  • Bir SELECT ... FOR UPDATE NOWAITveya yaparak bekleme işlemek için uygulamayı tasarlayın WAIT 2. Daha sonra satırı kilitleyememeyi yakalayabilir ve kullanıcıya başka bir oturumun aynı verileri değiştirdiğini bildirebilirsiniz.

7

Bir geliştirici bakış açısıyla cevap vereceğim.

Bence, açıkladığınız gibi bir satır çekişmesiyle karşılaştığınızda, bunun nedeni uygulamanızda bir hata olması. Çoğu durumda, bu tür bir çekişme, güncelleştirme kaybı güvenlik açığının bir işaretidir. AskTom'daki bu konu kayıp güncelleme kavramını açıklıyor:

Kayıp bir güncelleme şu durumlarda gerçekleşir:

oturum 1: Tom'un Çalışan kaydını okuyun

oturum 2: Tom'un Çalışan kaydını okuyun

oturum 1: Tom'un çalışan kaydını güncelleme

oturum 2: Tom'un çalışan kaydını güncelleme

Oturum 2, oturum 1'in değişikliklerini hiç görmeden YAZMAK - bu da güncellemenin kaybolmasına neden olur.

Kayıp güncellemenin kötü bir yan etkisi yaşadınız: oturum 2 henüz tamamlanmadığı için oturum 2 engellenebilir. Ancak asıl sorun, oturum 2'nin kaydı körü körüne güncellemesidir. Her iki oturumun da ifadeyi yayınladığını varsayalım:

UPDATE table SET col1=:col1, ..., coln=:coln WHERE id = :pk

Her iki deyimden sonra, session2 öğesinin, oturum 2 tarafından satır 1 tarafından değiştirildiği bildirilmeden değiştirildi.


Kayıp güncelleme (ve çekişme yan etkisi) asla olmamalı,% 100 önlenebilir. Bunları iki ana yöntemle önlemek için kilitleme kullanmalısınız: iyimser ve kötümser kilitleme .

1) Kötümser Kilitleme

Bir satırı güncellemek istiyorsunuz. Bu modda, o satırda bir kilit isteyerek başkalarının bu satırı değiştirmesini önleyeceksiniz ( SELECT ... FOR UPDATE NOWAITifade). Satır zaten değiştiriliyorsa, son kullanıcıya nazikçe çevirebileceğiniz bir hata iletisi alırsınız (bu satır başka bir kullanıcı tarafından değiştiriliyor). Satır mevcutsa, değişikliklerinizi yapın (GÜNCELLEME), ardından işleminiz ne zaman tamamlanırsa tamamlayın.

2) İyimser Kilitleme

Bir satırı güncellemek istiyorsunuz. Ancak, bu satırı kilitlemek istemezsiniz, belki de satırı güncellemek için birkaç işlem kullandığınızdan (web tabanlı vatansız uygulama) veya herhangi bir kullanıcının çok uzun süre kilit tutmasını istemediğinizden ( diğer kişilerin engellenmesine neden olabilir). Bu durumda hemen kilit istemezsiniz. Güncellemeniz yayınlandığında satırın değişmediğinden emin olmak için bir işaretçi kullanacaksınız. Tüm sütunların değerini önbelleğe alabilir veya otomatik olarak güncellenen bir zaman damgası sütunu veya sıra tabanlı bir sütun kullanabilirsiniz. Seçiminiz ne olursa olsun, güncellemenizi gerçekleştirmek üzereyken, aşağıdaki gibi bir sorgu göndererek o satırdaki işaretçinin değişmediğinden emin olursunuz:

SELECT <...>
  FROM table
 WHERE id = :id
   AND marker = :marker
   FOR UPDATE NOWAIT

Sorgu bir satır döndürürse, güncellemenizi yapın. Başlamazsa, bu, son sorguladığınızdan beri birisinin satırı değiştirdiği anlamına gelir. İşlemi baştan başlatmanız gerekecek.

Not: DB'nize erişen tüm uygulamalara karşı tam bir güveniniz varsa, iyimser kilitleme için doğrudan bir güncellemeye güvenebilirsiniz. Doğrudan yayınlayabilirsiniz:

UPDATE table
   SET <...>, 
       marker = marker + 1
 WHERE id = :id;

İfade hiçbir satırı güncellemezse, birisinin bu satırı değiştirdiğini ve baştan başlamanız gerektiğini bilirsiniz.

Tüm uygulamalar bu şema üzerinde anlaşırsa, asla başkası tarafından engellenmez ve kör güncellemeden kaçınırsınız. Ancak, satırı önceden kilitlemezseniz, başka bir uygulama, toplu iş veya doğrudan güncelleme iyimser kilitleme uygulamazsa yine de belirsiz kilitlemeye açık olursunuz. Bu yüzden, kilitleme şeması seçiminiz ne olursa olsun, her zaman satırı kilitlemenizi öneririm (satırı kilitlediğinizde, rowid dahil tüm değerleri aldığınız için performans isabeti ihmal edilebilir).

TL; DR

  • Bir satırı önceden kilitlemeden güncellemek, uygulamayı potansiyel "donmaya" maruz bırakır. DB'ye giden tüm DML iyimser veya kötümser kilitleme uygularsa bu önlenebilir.
  • SELECT deyiminin önceki herhangi bir SELECT ile tutarlı değerler döndürdüğünü doğrulayın (kaybolan güncelleme sorunlarından kaçınmak için)

5

Bu cevap muhtemelen The Daily WTF'e giriş için uygun olacaktır.

Doğru, oturumları izledikten ve aradıktan sonra USER_SOURCE- temel nedeni izledim

  • Sebep, şaşırtıcı bir şekilde kusurlu mantıktı
  • Son zamanlarda, SP'ye bir güncelleme ifadesi eklendi. Güncelleme ifadesi temel olarak tüm tabloyu güncelleyecektir. Görünüşe göre, söz konusu geliştirici, gerekli ifadeleri güncellemek için doğru cümleleri doğru eklemeyi unuttu.
  • Güncellenen tablo, en çok işlem yapılan tablolardan biri olan ve çok sayıda kayda sahip olan yukarıda belirtildiği gibidir. Güncelleme uzun ve acı verici bir zaman alacaktı.
  • Sonuç, diğer oturumların masada kilit alamaması ve satır kilidi içeriklerinde oturmasıdır.
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.