Benzersiz bir dizin ekleyemediğinizde kopyalardan kaçınmanın olası yolları nelerdir?


10

Bir eşzamanlılık sorununda sıkıştım.

Kullanıcının DB'de çoğaltılmaması gereken bazı verileri saklamak için 2 veya 3 işlem gönderdiği tipik bir sorundur, yinelenen bir kayıt olması durumunda bir hata döndürmeniz gerekir.

Bir karma depoladığınız bir sütuna bir dizin (benzersiz) ekleyebildiğinizde bu sorun kolaydır.

Ama bu durumda, büyük bir tablom var (muhtemelen milyonlarca kayıt) ve sadece tabloyu değiştiremiyorum.

Aslında, çoğaltılmaması gereken, ancak benzersiz bir dizin ayarlanmayan verilerin bir karmasını sakladığımız bir sütuna sahibiz.

Hala yinelenen alma, floş hemen önce var olup olmadığını kontrol etmek için benim java kodu üzerinde çalışıyorum.

Bunun için olası çözümlerim:

  • Eklemeye çalıştığım karmanın tabloda zaten var olup olmadığını kontrol eden bir tetikleyici oluşturun.
  • Bu tablo için benzersiz dizinler depolamak üzere başka bir tablo oluşturun ve ana tabloya bir yabancı anahtar ekleyin.
  • Fetal pozisyonda otur ve ağla

Karma çarpışmaları veya çekteki bir hata nedeniyle karma denetiminiz başarısız oluyor mu?
candied_orange

4
Sorunu ben anlamadım. Milyonlarca kayıt içeren tüm büyük tablonuz için bir kez endekslemek yerine, ekleyeceğiniz sonraki milyon kayıtların her birini, mevcut milyonları iki katına mı aramak istiyorsunuz? veya çekinizi yapmak için bazı bilgileri çoğaltın ve birleştirmeler ekleyin?
Christophe

Sorun şu ki, bu değişikliği yapmak için, hizmetimiz için çok fazla alana ve uzun bir kesinti süresine ihtiyacımız olduğu konusunda uyarıldım, bazı gereksinimleri yerine getirmek için hizmetimiz aylık 2 saatten fazla olamaz. En iyi yolun bu masada bir bakım yapmak olduğunu biliyorum, ancak şu anda yapamadığım bir şey, bu yüzden bir geçici çözüme ihtiyacımız var.
rafuru

4
Anlamıyorum - neden bir tetikleyici eklemek veya "bir dizin taklit" için başka bir tablo eklemek sadece varolan tabloya bir dizin eklemek daha az kesinti alır?
Doc Brown

2
@rafuru: benzersiz bir dizin oluşturmanız gerektiğini kim söyledi? Standart, benzersiz olmayan bir dizin, muhtemelen aynı karma değerine sahip tüm satırları hızlı bir şekilde bulmak için ihtiyacınız olan tek şey olacaktır.
Doc Brown

Yanıtlar:


3

Çözülmesi kolay birkaç olası senaryo ve olmayan zararlı bir senaryo var.

Bir değer girip bir süre sonra aynı değeri giren bir kullanıcı için INSERT sorunu algılayamadan önce basit bir SELECT (SEÇ) seçeneğini seçin. Bu, bir kullanıcının bir değer göndermesi ve bir süre sonra başka bir kullanıcının aynı değeri göndermesi durumunda işe yarar.

Kullanıcı, kodun tek bir çağrısında yinelenen değerlerin bir listesini gönderirse (örneğin, {ABC, DEF, ABC}), uygulama yinelenenleri algılayıp filtreleyebilir, belki de bir hata atar. Eklemeden önce DB'nin benzersiz değerlerden herhangi birini içermediğini de kontrol etmeniz gerekir.

Zor senaryo, bir kullanıcının yazma işlemi başka bir kullanıcının yazma işlemi ile aynı anda DBMS'nin içindeyse ve aynı değeri yazmasıdır. Sonra aralarında bir koşul var. DBMS (büyük olasılıkla - hangisini kullandığınızı söylemezsiniz) önleyici çoklu görev sistemi olduğundan, herhangi bir görev yürütmenin herhangi bir noktasında duraklatılabilir. Bu, user1'in görevinin mevcut bir satır olmadığını kontrol edebileceği anlamına gelir, daha sonra user2'nin görevi mevcut bir satır olmadığını kontrol edebilir, daha sonra user1'in görevi bu satırı ekleyebilir, daha sonra user2'nin görevi bu satırı ekleyebilir. Her noktada görevler bireysel olarak mutlu ve doğru olanı yapıyorlar. Ancak genel olarak bir hata oluşur.

Genellikle bir DBMS, söz konusu değere bir kilit koyarak bunu ele alır. Bu problemde yeni bir satır oluşturuyorsunuz, böylece kilitlenecek bir şey yok. Cevap bir aralık kilidi. Önerdiği gibi, şu anda var olsun ya da olmasın, bir dizi değeri kilitler. Bir kez kilitlendikten sonra, kilit bırakılana kadar bu aralığa başka bir görev tarafından erişilemez. Aralık kilitleri almak için SERİLEŞTİRİLEBİLİR yalıtım seviyesini belirlemeniz gerekir . Göreviniz kontrol edildikten sonra üst üste gizlice girme olgusu hayali kayıtlar olarak bilinir .

İzolasyon seviyesini tüm uygulama boyunca Seri hale getirilebilir olarak ayarlamanın sonuçları olacaktır. Üretilen olacaktır azaltılabilir. Geçmişte yeterince iyi çalışan diğer yarış koşulları şimdi hata göstermeye başlayabilir. Yinelenen kodunuzu yürüten ve uygulamanın geri kalanını olduğu gibi bırakan bağlantıya ayarlamanızı öneririm.

Kod tabanlı bir alternatif, yazmadan sonra öncekine göre kontrol etmektir. Öyleyse INSERT yapın, ardından bu karma değerine sahip satır sayısını sayın. Yinelenen işlemler varsa geri alın. Bunun sapkın sonuçları olabilir. Diyelim ki görev 1 yazıyor, sonra görev 2. Sonra görev 1 yineleniyor. İlk olmasına rağmen geri döner. Benzer şekilde, her iki görev de yinelenen ve her iki geri dönüşü algılayabilir. Ancak en azından çalışmak için bir mesajınız olacak, bir yeniden deneme mekanizması olacak ve yeni kopyalar olmayacak. Program akışını kontrol etmek için istisnalar kullanmak gibi, geri almalar kaşlarını çattı. Not iyi ki hepsiişlemde sadece yinelenen yazma yazma değil, geri alınır. Ve eşzamanlılığı azaltabilecek açık işlemlere sahip olmanız gerekir. Karma üzerinde bir dizin yoksa, yinelenen denetim korkunç yavaş olacaktır. Bunu yaparsanız, onu benzersiz bir hale getirebilirsiniz!

Yorumladığınız gibi, gerçek çözüm benzersiz bir indekstir. Bana öyle geliyor ki bu bakım pencerenize sığmalıdır (tabii ki sisteminizi en iyi biliyorsunuz). Diyelim ki karma sekiz bayt. Yüz milyon sıra için yaklaşık 1GB. Deneyim, makul bir donanımın bu birçok satırı bir veya iki dakika içinde işleyeceğini gösteriyor. Yinelenen kontrol ve eleme buna eklenir, ancak önceden yazılabilir. Yine de bu bir yana.


2

Aslında, çoğaltılmaması gereken, ancak benzersiz bir dizin ayarlanmayan verilerin bir karmasını sakladığımız bir sütunumuz var.

Karma çarpışmalarını kontrol etmek iyi bir ilk adımdır, ancak dikkatli olun, yeniden başlatıldığında aynı programın aynı veriler üzerinde aynı karma değerini üreteceğini garanti edemezsiniz . Birçok "hızlı" hash fonksiyonu, program başlangıç ​​zamanında tohumlanan dahili bir prng kullanır. Bu uygulamada yaptığınız gibi, karma ne olursa olsun her zaman aynı olması gerekiyorsa, kriptografik bir karma kullanın. İyi veya güvenli bir şifreleme karmasına ihtiyacınız olmadığını unutmayın.

İkinci adım, veri eşitliğini gerçekten kontrol etmektir, çünkü en iyi karma işlevleri bile bazen çarpışmalara neden olur, çünkü (genellikle) verilerinizin entropisini azaltırsınız.

Yani:

1.Adım: Şifreleme karma işleminde bir çarpışma olup olmadığını kontrol edin

2.Adım: Karmalar eşleşirse, gerçek verilerin aynı olup olmadığını kontrol edin


Bunun soruyu nasıl cevapladığını göremiyorum. Bir an için mevcut karma sütunun deterministik bir hash fonksiyonu ile doldurulduğunu varsayalım (aksi takdirde onu kullanma girişiminin hiçbir anlamı olmayacaktır). Anladığım kadarıyla, problem veritabanındaki o karma sütunda bir dizin bulunmamasıdır, bu nedenle cevabınızdaki ilk adım bile - bir çarpışma olup olmadığını kontrol etmek - bir tablodaki her yeni kayıt için tam bir masa taraması gerektirecektir. Muhtemelen çok yavaş olacak birkaç milyon kayıt.
Doc Brown

Sorunun sorduğu şey, bir dizin oluşturmadan yapabileceğiniz en iyisidir. Karma tarama en azından yalnızca bir sütunu kontrol etmeniz gerektiği anlamına gelir; bu, aksi takdirde kontrol etmek zorunda kalacakları birçok sütunu kontrol etmekten çok daha hızlıdır.
Turksarama

Bir dizin oluşturmak mümkün olmadığında bile eminim (bu durumda muhtemelen), OPs " Bu tablo için benzersiz dizinleri saklamak ve ana tabloya bir yabancı anahtar eklemek için başka bir tablo oluşturmak için" orijinal öneri çok yapar daha mantıklı.
Doc Brown

Deterministik karma ve kriptografik karma iki dikey kavramdır değil mi? bir kriptografik karma deterministik olmayabilir ve tam tersi de deterministik bir karma çok iyi kriptografik güce sahip olamaz.
Newtopian

Aynı şey değiller, ama dik de değiller. Kriptografik karmalar deterministik karmaların bir alt kümesidir, ancak özellikle bir nedenden ötürü geri dönüşümlü olmasını istemediğiniz sürece kimse gerçekten kriptografik olmayan deterministik hashlar yapmaz.
Turksarama

2

Benzersiz bir birincil anahtarla yeni bir tablo oluşturma

İstemci tarafında, basit kayıtları yeniden tespit edebilmeniz için her kayıt için GUID oluşturmaya başlayın.

En azından yeni veriler için iyi olacak şekilde yeni kayıtları yeni tabloya koyun.

"CheckedAgainstOldData" adlı yeni tabloda bir sütun var

Geçerli yavaş karma denetimini yaptığınız her şeyi yapan bir arka uç görevine sahip olun, eski verilerde bir kopya bulabileceğini ve bayrağı buna göre ayarlayıp ayarlayamayacağını, bu noktada tekrarları reddedip istemciye bir bildirim gönderme olduğunu görmektir.

Bu arada, verileri eski tablodan yeni tabloya taşıyan, karma denetiminizle yinelenenleri kontrol eden ve GUID üreten başka bir arka uç görevi var.

Bu görevi birkaç gün boyunca (gerekirse) çalışır durumda bırakarak, verileri kesinti süresi olmadan aktarabilirsiniz.

Aktarım tamamlandıktan sonra yavaş "CheckedAgainstOldData" işlemini kapatabilirsiniz. ve tüm verileri tek bir tabloya aktarın.

Açıkçası, sorun tanımladığınız kadar kötü ve yazılım eskiyse, binlerce kopyaya sahip olacaksınız.


1

"Kullanıcı" dan gelen verilerin bir klavyede oturan biri anlamına geldiği ve kopyaların aynı anda aynı verilere giren iki kullanıcıdan kaynaklandığı varsayılarak. Tetikleyicinin başında rastgele bir gecikmeye neden olan bir işlev eklemeyi deneyin. Tabloya yeni bir kayıt yazmak için en az uzun bir süre ve muhtemelen bir nanosentrenden daha fazla olmayan bir kayıt verin. Bu şekilde dupe istekleri alırken ilk istek yapılmalı ve varlık tetikleyicisi doğru sonucu geri atmalıdır. (Açıklama: her çağrı ALOHA protokolü ile aynı prensipler boyunca kendi benzersiz rastgele gecikme süresine sahip olmalı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.