2010-02-15 139 views
3

我目前正在從一個數據庫提取表到另一個數據庫的SSIS包。兩個數據庫中的表都使用與主鍵相同的列。我選擇語句來提取數據是一個簡單的選擇語句。當我運行包時,我收到一個錯誤,那裏有重複的主鍵值。SQL Server查詢返回多行

我回顧了我的select語句並驗證了我的select語句沒有返回重複的行。因此,爲了測試這一點,我從表格中刪除了主鍵,並將數據插入到SSIS包中。它運行後,我看着桌子,看看哪些行被複制。我發現,在提取器在被複制的地方進行編輯時,在編輯之前有一行記錄,在編輯之後記錄了它。我可以很容易地告訴它,因爲表中有一個最後修改的字段,每次更新記錄時都會更新。

我在我的select語句中添加了一個NOLOCK提示,並且它停止返回重複的行。

所以我的問題是爲什麼?我會預期,帶有NOLOCK表提示的select語句將返回重複行的機會更大,因爲它沒有使用鎖定,並且沒有NOLOCK提示的select語句應該使用鎖定來確保它不返回重複行。

這是我用來選擇數據的select語句。我沒有驗證連接並不導致其重複的行:

SELECT pe.enc_id, 
     pe.enc_nbr, 
     pe.billable_ind, 
     pe.clinical_ind AS clinical_ind, 
     pe.budget_ind, 
     pe.print_stmt_ind, 
     pe.send_coll_letter_ind, 
     pe.outsource_exempt_ind, 
     cb.First_name + ' ' + cb.last_name AS CreatedBy, 
     pe.create_timestamp AS create_timestamp, 
     mb.first_name + ' ' + mb.last_name AS ModifiedBy, 
     pe.modify_timestamp AS modify_timestamp 
FROM patient_encounter pe WITH(NOLOCK) 
     LEFT OUTER JOIN user_mstr cb WITH(NOLOCK) ON 
      pe.created_by = cb.user_id 
     LEFT OUTER JOIN user_mstr mb WITH(NOLOCK) ON 
      pe.modified_by = mb.user_id 

回答

0

的使用NOLOCK提示只是告訴數據庫服務器忽略了鎖,並從數據庫中只選擇當前值 - 因此它只是選擇了所有當前行的值在它到達該行時。

請注意,您不會在正在更新的行的新表中獲取更新。

沒有看到你的SQL,我猜測它的構造方式,它抓住當前行,等待鎖定清除,然後選擇新行。

鎖定整個表格將防止更改/重複,但您可能會在選擇時鎖定每個人不在表格中。

編輯: FYI備選方案:使用由其他進程鎖定READPAST-行被跳過,在表級別當然會阻塞其他進程,並且可能不期望 TABLOCK鎖。

注意:在事務寫入期間UPDLOCK被轉換爲XLOCK。

提示有兩個類別:粒度和隔離級別。粒度包括PAGLOCK,NOLOCK,ROWLOCK和TABLOCK。隔離級別提示包括HOLDLOCK,NOLOCK,READCOMMITTED,REPEATABLEREAD和SERIALIZABLE。每組最多可以使用一個。

EDIT2:只是爲了完整性:READCOMMITTED-只從已提交的事務中讀取數據。這是默認行爲。編輯3:更多信息:NOLOCK將讀取行,但是如果ROLLBACK發生在可能影響所選集的準確性的事務處理中,則會冒着讀取「髒」數據的風險,這些數據將不會存在或具有不存在的數據。

其他重要信息是發現交易正在使用什麼類型的鎖,以便您可以相應地進行規劃。

+0

感謝您的信息。我在帖子中添加了我正在使用的select語句。 爲什麼要搶兩行?第一次讀它之後,爲什麼更改記錄會導致它再次讀取它? –

+0

請記住,即使您不使用NOLOCK,服務器也可以覆蓋「提示」,但它可以在內部使用,因此可以使用重複的行。 –

+0

偉大的觀點,謝謝。無論如何要告訴內部使用什麼? –

1

NOLOCK提示會導致髒讀取異常,而其中一種異常是重複讀取。這樣的讀取十分頻繁,如果更新更改了行通過查詢掃描索引的位置:

  • 說你在表2行,有一個ID鍵,行與關鍵值1和2
  • 一個請求(T1)運行UPDATE表SET key = 3 WHERE key = 1;
  • 第二個請求(T2)運行SELECT ... FROM WITH WITH(NOLOCK);
  • T1鎖定與鍵值的行1
  • T2忽略鎖定T1具有和與關鍵值1
  • T2繼續讀取的行和與關鍵值讀取行2
  • T1更新該行,並且排在他新的鍵值位置3
  • T2繼續掃描索引INT移動,並與鍵值3

所以選擇了讀取的行兩次,一次同時有鑰匙讀取行值1,一次它有一個關鍵值3.這只是一個會發生什麼的微不足道的例子。實際上,更復雜的查詢可以運行復雜的計劃並使用其他索引,所有索引都受到這種異常情況的影響。

總之:NOLOCK暗示是邪惡的。如果您想避免爭用,請使用snapshot isolation

+0

感謝您的回覆,以及NOLOCK的絕佳解釋。令我困惑的不是當我使用NOLOCK時發生這種情況,而是當我不使用NOLOCK時發生這種情況。主鍵列沒有被更改,記錄有更新的非ID字段,並且當我不使用NOLOCK時它正在被讀取兩次。 –

+0

對不起,在對角線閱讀您的問題,實際上完全忽略了這一點。 –

+0

您能否顯示在提取過程中發生的編輯示例? –