SQL Server 中WITH (NOLOCK)淺析

來源:互聯網
上載者:User

標籤:des   style   blog   http   io   color   ar   os   使用   

概念介紹

  

開發人員喜歡在SQL指令碼中使用WITH(NOLOCK), WITH(NOLOCK)其實是表提示(table_hint)中的一種。它等同於 READUNCOMMITTED 。 具體的功能作用如下所示(摘自MSDN):

   1: 指定允許髒讀。不發布共用鎖定來阻止其他事務修改當前事務讀取的資料,其他事務設定的獨佔鎖定不會阻礙當前事務讀取鎖定資料。允許髒讀可能產生較多的並行作業,但其代價是讀取以後會被其他交易回復的資料修改。這可能會使您的事務出錯,向使用者顯示從未提交過的資料,或者導致使用者兩次看到記錄(或根本看不到記錄)。有關髒讀、不可重複讀取和幻讀的詳細資料,請參閱並發影響。

   2: READUNCOMMITTED 和 NOLOCK 提示僅適用於資料鎖。所有查詢(包括那些帶有 READUNCOMMITTED 和 NOLOCK 提示的查詢)都會在編譯和執行過程中擷取 Sch-S(架構穩定性)鎖。因此,當並發事務持有表的 Sch-M(架構修改)鎖時,將阻塞查詢。例如,資料定義語言 (Data Definition Language) (DDL) 操作在修改表的架構資訊之前擷取 Sch-M 鎖。所有並發查詢(包括那些使用 READUNCOMMITTED 或 NOLOCK 提示啟動並執行查詢)都會在嘗試擷取 Sch-S 鎖時被阻塞。相反,持有 Sch-S 鎖的查詢將阻塞嘗試擷取 Sch-M 鎖的並發事務。有關鎖行為的詳細資料,請參閱鎖相容性(資料庫引擎)。

   3:  不能為通過插入、更新或刪除操作修改過的表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查詢最佳化工具忽略 FROM 子句中應用於 UPDATE 或 DELETE 語句的目標表的 READUNCOMMITTED 和 NOLOCK 提示。

 

功能與缺陷

 

    使用WIHT(NOLOCK)有利也有弊,所以在決定使用之前,你一定需要瞭解清楚WITH(NOLOCK)的功能和缺陷,看其是否適合你的業務需求,不要覺得它能提升效能,稀裡糊塗的就使用它。

 

    1:使用WITH(NOLOCK)時查詢不受其它獨佔鎖定阻塞

    開啟會話視窗1,執行下面指令碼,不提交也不復原事務,類比事務真在執行過程當中

BEGIN TRAN
 
       UPDATE TEST SET NAME=‘Timmy‘ WHERE OBJECT_ID =1;
 
       --ROLLBACK
 

   

   開啟會話視窗2,執行下面指令碼,你會發現執行結果一直查詢不出來(其實才兩條記錄)。當前會話被阻塞了

SELECT * FROM TEST;

    開啟會話視窗3,執行下面指令碼,查看阻塞情況,你會發現在會話2被會話1給阻塞了,會話2的等待類型為LCK_M_S:“當某任務正在等待擷取共用鎖定時出現”

 
 
  SELECT wt.blocking_session_id                    AS BlockingSessesionId
        ,sp.program_name                           AS ProgramName
        ,COALESCE(sp.LOGINAME, sp.nt_username)     AS HostName    
        ,ec1.client_net_address                    AS ClientIpAddress
        ,db.name                                   AS DatabaseName        
        ,wt.wait_type                              AS WaitType                    
        ,ec1.connect_time                          AS BlockingStartTime
        ,wt.WAIT_DURATION_MS/1000                  AS WaitDuration
        ,ec1.session_id                            AS BlockedSessionId
        ,h1.TEXT                                   AS BlockedSQLText
        ,h2.TEXT                                   AS BlockingSQLText
  FROM sys.dm_tran_locks AS tl
  INNER JOIN sys.databases db
    ON db.database_id = tl.resource_database_id
  INNER JOIN sys.dm_os_waiting_tasks AS wt
    ON tl.lock_owner_address = wt.resource_address
  INNER JOIN sys.dm_exec_connections ec1
    ON ec1.session_id = tl.request_session_id
  INNER JOIN sys.dm_exec_connections ec2
    ON ec2.session_id = wt.blocking_session_id
  LEFT OUTER JOIN master.dbo.sysprocesses sp
    ON SP.spid = wt.blocking_session_id
  CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
  CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2

 

 

 

此時查看會話1(會話1的會話ID為53,執行指令碼1前,可以用SELECT  @@spid查看會話ID)的鎖資訊情況,你會發現表TEST(ObjId=1893581784)持有的鎖資訊如下所示

 

   

開啟會話視窗4,執行下面指令碼.你會發現查詢結果很快就出來,會話4並不會被會話1阻塞。

    SELECT * FROM TEST WITH(NOLOCK)

從上面類比的這個小例子可以看出,正是由於加上WITH(NOLOCK)提示後,會話1中事務設定的獨佔鎖定不會阻礙當前事務讀取鎖定資料,所以會話4不會被阻塞,從而提升並發時查詢效能。

 

2:WITH(NOLOCK) 不發布共用鎖定來阻止其他事務修改當前事務讀取的資料,這個就不舉例子了。

本質上WITH(NOLOCK)是通過減少鎖和不受排它鎖影響來減少阻塞,從而提高並發時的效能。所謂凡事有利也有弊,WITH(NOLOCK)在提升效能的同時,也會產生髒讀現象。

如下所示,表TEST有兩條記錄,我準備更新OBJECT_ID=1的記錄,此時事務既沒有提交也沒有復原

BEGIN TRAN 
 
UPDATE TEST SET NAME=‘Timmy‘ WHERE OBJECT_ID =1; 
 
--ROLLBACK 
 

此時另外一個會話使用WITH(NOLOCK)查到的記錄為未提交的記錄值

假如由於某種原因,該交易回復了,那麼我們讀取到的OBJECT_ID=1的記錄就是一條髒資料。

髒讀又稱無效資料的讀出,是指在資料庫訪問中,事務T1將某一值修改,然後事務T2讀取該值,此後T1因為某種原因撤銷對該值的修改,這就導致了T2所讀取到的資料是無效的。

 

WITH(NOLOCK)使用情境

 

什麼時候可以使用WITH(NOLOCK)? 什麼時候不能使用WITH(NOLOCK),這個要視你系統業務情況,綜合考慮效能情況與業務要求來決定是否使用WITH(NOLOCK), 例如涉及到金融或會計成本之類的系統,出現髒讀那是要產生嚴重問題的。關鍵業務系統也要謹慎考慮。大體來說一般有下面一些情境可以使用WITH(NOLOCK)

   1: 基礎資料表,這些表的資料很少變更。

   2:曆史資料表,這些表的資料很少變更。

   3:業務允許髒讀情況出現涉及的表。

   4:資料量超大的表,出於效能考慮,而允許髒讀。

另外一點就是不要濫用WITH(NOLOCK),我發現有個奇怪現象,很多開發知道WITH(NOLOCK),但是有不瞭解髒讀,習慣性的使用WITH(NOLOCK)。

 

WITH(NOLOCK)與 NOLOCK區別

 

為了搞清楚WITH(NOLOCK)與NOLOCK的區別,我查了大量的資料,我們先看看下面三個SQL語句有啥區別

    SELECT * FROM TEST NOLOCK

    SELECT * FROM TEST (NOLOCK);

    SELECT * FROM TEST WITH(NOLOCK);

上面的問題概括起來也就是說NOLOCK、(NOLOCK)、 WITH(NOLOCK)的區別:

1: NOLOCK這樣的寫法,其實NOLOCK其實只是別名的作用,而沒有任何實質作用。所以不要粗心將(NOLOCK)寫成NOLOCK

2:(NOLOCK)與WITH(NOLOCK)其實功能上是一樣的。(NOLOCK)只是WITH(NOLOCK)的別名,但是在SQL Server 2008及以後版本中,(NOLOCK)不推薦使用了,"不藉助 WITH 關鍵字指定表提示”的寫法已經過時了。 具體參見MSDN http://msdn.microsoft.com/zh-cn/library/ms143729%28SQL.100%29.aspx

    2.1  至於網上說WITH(NOLOCK)在SQL SERVER 2000不生效,我驗證後發現完全是個謬論。

    2.2  在使用連結的伺服器的SQL當中,(NOLOCK)不會生效,WITH(NOLOCK)才會生效。如下所示

    訊息 4122,層級 16,狀態 1,第 1 行

    Remote table-valued function calls are not allowed.

 

WITH(NOLOCK)會不會產生鎖

    很多人誤以為使用了WITH(NOLOCK)後,資料庫庫不會產生任何鎖。實質上,使用了WITH(NOLOCK)後,資料庫依然對該表對象產生Sch-S(架構穩定性)鎖以及DB類型的共用鎖定, 如下所示,可以在一個會話中查詢一個大表,然後在另外一個會話中查看鎖資訊(也可以使用SQL Profile查看會話鎖資訊)

    不使用WTIH(NOLOCK)

  使用WITH(NOLOCK)

  從上可以看出使用WITH(NOLOCK)後,資料庫並不是不產生相關鎖。  對比可以發現使用WITH(NOLOCK)後,資料庫只會產生DB類型的共用鎖定、以及TAB類型的架構穩定性鎖.

另外,使用WITH(NOLOCK)並不是說就不會被其它會話阻塞,依然可能會產生Schema Change Blocking

會話1:執行下面SQL語句,暫時不提交,類比事務正在執行

BEGIN TRAN 
 
  ALTER TABLE TEST ADD Grade VARCHAR(10) ; 
 

會話2:執行下面語句,你會發現會話被阻塞,如下所示。

SELECT * FROM TEST WITH(NOLOCK)

SQL Server 中WITH (NOLOCK)淺析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.