2012-09-26 71 views
48

我想知道如果僅影響該表的其他查詢是SELECT查詢,那麼在表上使用SELECT WITH (NOLOCK)有什麼好處。瞭解SELECT查詢中的SQL Server LOCKS

SQL Server如何處理? SELECT查詢會阻止另一個SELECT查詢嗎?

我正在使用SQL Server 2012和Linq-to-SQL DataContext

(EDIT)

關於性能:

  • 會第2個SELECT必須等待1 SELECT到如果使用的是鎖定SELECT完成?
  • 與a SELECT WITH (NOLOCK)

謝謝。

回答

111

在SQL Server將放在桌子排共享鎖一個SELECT - 和第二SELECT也需要一個共享鎖,而這些都是相互兼容。

所以沒有人SELECT不能阻止另一個SELECT

查詢提示用於的WITH (NOLOCK)的功能是能夠讀取正在插入(通過另一個連接)過程中尚未提交的數據。

如果沒有查詢提示,一個SELECT可能會阻止由放在行的獨家鎖(也可能是整個表)正在進行INSERT(或UPDATE)語句讀取表,直到該操作的事務已被提交(或回滾)。

問題WITH (NOLOCK)提示是:您可能正在讀取根本不會被插入的數據行(最後如果INSERT事務被回滾) - 那麼您的例如報告可能會顯示從未真正提交到數據庫的數據。

還有另一個可能有用的查詢提示 - WITH (READPAST)。這指示SELECT命令只跳過它嘗試讀取的所有行並且僅被鎖定。 SELECT不會阻塞,它不會讀取任何「髒」未提交的數據 - 但它可能會跳過一些行,例如不會顯示錶格中的所有行。

+1

很好的答案,非常感謝!會不會有影響(在數百個'SELECT'查詢中)無理地使用'WITH(NOLOCK)'? –

+1

我們在99.5%的選擇中使用了nolock,沒有開玩笑。如果管理員正在更新用戶記錄,則不希望其導致報告在此處等待整個分佈式事務處理完成。所以他們的舊數據顯示在報告中。誰在乎?如果報告已經在那之前運行了一秒鐘,那麼就是與rowlock一樣的數據。唯一值得關注的是尚未確定的數據。如果您顯示的是「最近一小時內的訂單」,這可能是一個問題,但與速度/併發增益相比,這是一個微小的問題。 –

+2

此外,由於「報告」被作爲示例拋出,報告通常是在過去5分鐘的時間段內。使用nolock報告上個月的數據 - 好像這些數據不會在一個月後回滾。 –

1

選擇不鎖 - 將選擇可能會/可能不會被插入的記錄。你會讀一個髒數據。

例如 - 讓一個事務插入1000行然後失敗。

當你選擇 - 你會得到1000行。

+0

但是如果沒有記錄意圖插入該表中,NO LOCK是否仍然相關? –

+0

不,它不是。因爲read使用一個共享鎖,可以通過多個會話獲取該鎖。沒有辦法弄髒數據。 –

+0

並在性能POV? –

6

在我的工作中,我們有一個非常大的系統,可以同時運行在許多PC上,非常大的表格有成千上萬行,有時甚至有數百萬行。

當你在一個非常大的表上做SELECT時,假設你想知道用戶在過去10年中所做的每個事務,並且表的主鍵不是以有效的方式構建的,查詢可能需要幾分鐘才能運行。

然後,我們的應用程序可能會同時在許多用戶的PC上運行,訪問同一個數據庫。因此,如果有人試圖插入到另一個SELECT正在讀取的表中(在SQL試圖讀取的頁面中),那麼可能會發生LOCK並且兩個事務彼此阻塞。

我們必須在我們的SELECT語句中添加一個「NO LOCK」,因爲它是一個巨大的SELECT選擇,在很多用戶的同時使用很多,而且我們一直都有LOCKS。

我不知道我的例子是否足夠清楚?這是一個真實的例子。

+0

謝謝你的例子,但我只想知道SELECT查詢影響其他SELECT查詢(在同一張表上).. –

+1

他們不會,但是select語句可能是包含更新的事務的一部分。更新tbl set x =(從tbl選擇max(y))其中z =(從tbl選擇min(a))。如果你有一個來自tbl的併發選擇z,其他選擇不會阻止它,但更新是。 –

+0

我正好有這個問題,長時間運行的選擇阻止了我的插入。 – nojetlag

22

關於性能,您不斷關注選擇。
共享不會阻止讀取。
共享鎖塊更新。
如果您擁有數百個共享鎖,則需要一段時間的更新才能獲得排它鎖,因爲它必須等待共享鎖清除。

默認情況下,select(讀取)採用共享鎖。
共享(S)鎖定允許併發事務讀取(SELECT)資源。
共享鎖定對其他選擇(1或1000)沒有影響。

區別在於nolock與共享鎖效果如何更新或插入操作。

當資源上存在共享(S)鎖定時,沒有其他事務可以修改數據。

共享鎖會阻止更新!
但nolock不會阻止更新。

這可能會對更新的性能產生巨大影響。它也影響插入。

髒讀(nolock)聽起來很髒。你永遠不會獲得部分數據。如果更新將John改爲Sally,你永遠不會得到Jolly。

我使用共享鎖很多併發。數據一讀完就會陳舊。對下一毫秒改變爲Sally的約翰的閱讀是陳舊的數據。讀下一個毫秒的Sally回滾約翰是陳舊的數據。這是在毫秒級別。我有一個數據採集器,如果用戶使用共享鎖,需要20個小時才能運行,並且運行4個小時是用戶不會鎖定的。在這種情況下,共享鎖導致數據失效16個小時。

不要使用nolocks錯誤。但他們確實有一席之地。如果你打算在一個字節被設置爲1時削減支票,然後在支票被削減時將它設置爲2 - 而不是一個nolock的時間。

+1

謝謝。我們看到類似的性能特點。如果我們需要讀取鎖定,我們的網站將不會運行,並且在大多數情況下沒有它的影響是微不足道的。 –

+0

@BrianWhite謝謝。有人得到它。我更新和插入了很多表鎖。進入,完成它,走出去是我的方法。 – Paparazzi

+1

髒讀(nolock)聽起來很髒。你永遠不會獲得部分數據。如果更新將John改爲Sally,你永遠不會得到Jolly。 - 我們讀約翰吧? – MonsterMMORPG

2

SELECT WITH (NOLOCK)允許讀取未提交的數據,這相當於在數據庫上設置了READ UNCOMMITTED隔離級別。 NOLOCK關鍵字允許比設置整個數據庫的隔離級別更細粒度的控制。

維基百科有一個有用的文章:Wikipedia: Isolation (database systems)

它是在長度在其他計算器文章還討論。

+0

感謝rghome您提供的其他信息。 –

+0

這就是爲什麼我更喜歡使用'READUNCOMMITTED'('NOLOCK'的別名)提示,*當*這是一個有效的用例時。這樣做會使實際操作不那麼「真正」無鎖「,不太明顯。 – user2864740

7

我得添加一個重要的評論。大家都在提及NOLOCK只讀取髒數據。這並不準確。在閱讀過程中,您可能會獲得相同的行兩次或整行被跳過。原因是,當SQL Server重新平衡B樹時,您可以在同一時間詢問一些數據。

檢查另一個線程

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx

隨着NOLOCK提示(或設置會話的隔離級別讀取未提交的),你告訴你沒有的SQL Server期待一致性,所以沒有保證。請記住,「不一致的數據」不僅意味着您可能會看到稍後回滾的未提交更改,或數據更改處於事務的中間狀態。 這也意味着在掃描所有表/索引數據的簡單查詢中,SQL Server可能會丟失掃描位置,或者您最終可能會獲得同一行兩次。