2013-03-13 19 views
5

I değerleri benim geçici tablo seçer ve böylece gibi veritabanına bunları ekler saklı bir yordam koşuyorum SEÇ saatte binlerce istekleri işleyen bir sunucuda saatlerce), daha sonra EmailAddress sütununda bir dizinde "UNIQUE KEY kısıtlaması ihlali" gibi benzersiz bir kısıtlama hatası alıyorum.INSERT INTO .. ​​.. benzersiz kısıtlama ihlali

Yinelenen değerler arasında geçiş yapmadığımı onaylarım. Olsa bile, DISTINCT tarafından yakalanmalı.

-SQL Server 2008 -Stored proc + SELECT ve ardından gelen INSERT arasında, bir INSERT tamamladı aynı/farklı saklanan proc başka arama yapıldı Bu olabilir + JDBC CallableStatement

işlemleri kullanmıyor benzer verilerle mi? Eğer öyleyse, bunu önlemenin en iyi yolu ne olurdu?

Bazı fikirler: Üretimde bir kerede bu SQL Server ile iletişim kuran çok sayıda "istemciler" örneğimiz var, bu yüzden ilk tepkimem bir eşzamanlılık sorunuydu, ancak bunu kendim kopyalayamıyorum. Yaptığım en iyi tahmin, ama şimdiye kadar hiçbir yere gitmedi. Bu, üretim ortamıyla karşılaştırıldığında yükün önemsiz olduğu evreleme ortamımızda gerçekleşmez. Eşzamanlılık sorunlarına bakmaya başladığım ana sebep buydu.

+1

EmailAddress öğesindeki her iki taraftaki NULL değeri, benzersiz anahtar kısıtlamayı ihlal edebilir. Bu sütun geçersizse, eki 'mevcut' olarak yeniden yazabilirsiniz. –

+0

İyi nokta. Koddaki boş değerlere karşı kontrol yaparım, ancak sanırım tekrar sql'de kontrol edebilirim. –

cevap

5

Hata, büyük olasılıkla aynı anda bir ekleme yürüten iki oturumdan kaynaklanıyor.

SQL kodunuzu MERGE kullanarak daha güvenli hale getirebilirsiniz. Aaron Bertrand'ın yorumu gibi (teşekkürler!), you have to include a with (holdlock) hint to make merge really safe diyor.

; merge emails e with (holdlock) 
using #EmailInfoTemp eit 
on  e.EmailAddress = eit.EmailAddress 
when not matched then insert 
     (EmailAddress) values (eit.EmailAddress) 

merge deyimi kontrol edip "insert" "eşleşmedi" oluyor arasında başka hiçbir oturum gizlice sağlamak için uygun kilitleri alacaktır.

merge'u kullanamıyorsanız, istemci tarafındaki sorunu çözebilirsiniz. İki ekin aynı anda çalışmadığından emin olun. Bu genellikle bir mutex veya başka bir senkronizasyon yapısı ile yapmak kolaydır.

+1

[Bir HOLDLOCK ipucu eklemediğiniz sürece MERGE' daha güvenli olmayabilir (http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx). –

+0

@AaronBertrand: Teşekkürler. MERGE için MSDN sayfası, "[TARGET İLE GEÇERLİ DEĞİLDEN SONRA READPAST'i Belirtme” yazıyor. SONA ERMEK, UNIQUE kısıtlamalarını ihlal eden INSERT işlemlerine neden olabilir. " Bu yüzden 'readpast' belirtmediğiniz sürece güvenli olduğunu düşündüm. – Andomar

+1

evet Microsoft'un genellikle kırılabileceği tüm durumları belgelemesi olası değildir. Dokümantasyon aynı zamanda [henüz çözülmemiş olan bu hataların herhangi biri hakkında konuşmuyor (aşağıya doğru ilerleyin)] (http://www.sqlperformance.com/2013/02/t-sql-queries/another- birleştirme-bug). :-) –