1. 程式人生 > >SQLServer之鎖定資料庫表

SQLServer之鎖定資料庫表

使用者鎖定表注意事項

通過指定鎖定方法、一個或多個索引、查詢處理操作(如表掃描或索引查詢)或其他選項,表提示在資料操作語言 (DML) 語句執行期間覆蓋查詢優化器的預設行為。表提示在 DML 語句的 FROM 子句中指定,僅影響在該子句中引用的表或檢視。

如果查詢計劃不訪問表,則將忽略表提示。 這可能是由於優化器選擇了完全不訪問該表,也可能是因為改成了訪問索引檢視。 在後一種情況中,使用 OPTION (EXPAND VIEWS) 查詢提示可阻止訪問索引檢視。

所有鎖提示將傳播到查詢計劃訪問的所有表和檢視,其中包括在檢視中引用的表和檢視。 另外, SQL Server 還將執行對應的鎖一致性檢查。

獲取行級別鎖的鎖提示 ROWLOCK、UPDLOCK 和 XLOCK 可能對索引鍵而不是實際的資料行採用鎖。 例如,如果表具有非聚集索引,而且由涵蓋索引處理使用鎖提示的 SELECT 語句,則獲得的鎖針對的是涵蓋索引中的索引鍵,而不是基表中的資料行。

如果表包含計算列,而該計算列是由訪問其他表中的列的表示式或函式計算的,則不在這些表中使用表提示,並且不會傳播這些提示。 例如,在查詢的表中指定 NOLOCK 表提示。 此表包含的計算列是由訪問另一表中的列的表示式和函式組合計算的。 表示式和函式引用的表在被訪問時將不使用 NOLOCK 表提示。

對於 FROM 子句中的每個表, SQL Server 不允許存在多個來自以下各個組的表提示:

粒度提示:PAGLOCK、NOLOCK、READCOMMITTEDLOCK、ROWLOCK、TABLOCK 或 TABLOCKX。
隔離級別提示:HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD 和 SERIALIZABLE。

使用T-SQL指令碼新增、查詢、刪除鎖

新增表鎖:

語法:

select * from 表名 as 別名 with(<table_hint> [ [, ]...n ]);

<table_hint> ::= [ noexpand] { index( index_value [ ,...n ] ) | index= ( index_value ) | forceseek[( index_value ( index_column_name [ ,... ] ) ) ] | forcescan | forceseek | holdlock | nolock | nowait | paglock | readcommited | readcommitedlock | readpast | readuncommitted | repeatableread | rowlock | serializable | snapshot | spatial_window_max_cells= integer | tablock | tablockx | updlock | xlock };

語法解析:

--noexpand
--指定查詢優化器處理查詢時,不擴充套件任何索引檢視來訪問基礎表。查詢優化器將檢視當成包含聚集索引的表處理。 NOEXPAND 僅適用於索引檢視。

--index(index_value [,... n ] ) | index = ( index_value)
--index()語法指定供查詢優化器在處理該語句時使用的一個或多個索引的名稱或 ID。 另一供選擇的 index = 語法指定單個索引值。 只能為每個表指定一個索引提示。
--如果存在聚集索引,則 index(0) 強制執行聚集索引掃描,index(1) 強制執行聚集索引掃描或查詢。 如果不存在聚集索引,則 index(0) 強制執行表掃描,index(1) 被解釋為錯誤。
--如果在單個提示列表中使用了多個索引,則會忽略重複項,其餘列出的索引將用於檢索表中的行。 索引提示中的索引順序很重要。 多索引提示還強制執行索引 AND 運算,查詢優化器將對所訪問的每個索引應用盡可能多的條件。
--如果提示索引的集合並未包含查詢引用的所有列,則會在 SQL Server 資料庫引擎檢索所有索引列後執行提取操作以檢索其餘列。

--forceseek[(index_value(index_column_name [ ,... n ] )) ]
--指定查詢優化器僅使用索引查詢操作作為表或檢視中的資料的訪問途徑。
--index_value
--是索引名稱或索引 ID 值。 不能指定索引 ID 0(堆)。 若要返回索引名稱或 ID,請查詢 sys.indexes 目錄檢視。
--index_column_name
--是要包含在查詢操作中的索引列的名稱。指定帶索引引數的forceseek類似於將forceseek與INDEX提示一起使用。但是,您可以通過指定要查詢的索引和查詢操作中要考慮的索引列,更好地控制查詢優化器使用的訪問路徑。 該優化器可以根據需要考慮其他列。
--使用forceseek提示(具有或不帶索引引數)時,考慮以下準則:
--該提示可以指定為表提示或查詢提示。 有關查詢提示的詳細資訊,請參閱查詢提示 (Transact-SQL)。
--若要將forceseek應用到索引檢視,還必須指定NOEXPAND提示。
--對每個表或檢視最多應用該提示一次。
--不能為遠端資料來源指定該提示。 帶索引提示指定forceseek時,將返回錯誤7377;不帶索引提示使用forceseek時,將返回錯誤8180。
--如果forceseek導致找不到計劃,將返回錯誤8622。
--使用索引引數指定forceseek時,遵循以下準則和限制:
--不能為作為INSERT、UPDATE或DELETE語句的目標的表指定該提示。
--該提示不能與INDEX提示或另一個forceseek提示一起指定。
--至少必須指定一個列且該列為第一個鍵列。
--可以指定其他索引列,但是不能跳過鍵列。 例如,如果指定的索引包含鍵列 a、b 和 c,則有效的語法應包含forceseek(MyIndex (a))和forceseek(MyIndex (a, b)。無效的語法應包含 FORCESEEK (MyIndex (c)) 和 FORCESEEK (MyIndex (a, c)。
--在提示中指定的列名順序必須與引用的索引中列的順序匹配。
--不能指定不在索引鍵定義中的列。 例如,在非聚集索引中,只能指定定義的索引鍵列。 不能指定自動包含在索引中的聚集鍵列,但是優化器可以使用這些列。
--xVelocity 記憶體優化的列儲存索引不能作為索引引數指定。 返回錯誤 366。
--修改索引定義(例如通過新增或刪除列)可能需要修改引用該索引的查詢。
--該提示阻止優化器考慮表的任何空間或 XML 索引。
--該提示不能與FORCESCAN提示一起指定。
--對於分割槽的索引,不能在 FORCESEEK 提示中指定 SQL Server 隱式新增的分割槽列。

--forcescan
--適用於:通過 SQL Server 2017 的 SQL Server 2008 R2 SP1。
--指定查詢優化器僅使用索引掃描操作作為引用的表或檢視的訪問途經。對於優化器低估受影響的行數並選擇一個查詢操作而非掃描操作的查詢,forcescan提示很有用。 出現這樣的情況時,授予該操作的記憶體量太小,查詢效能將受影響。
--指定forcescan時有無INDEX提示均可。與索引提示組合使用 (INDEX = index_name, forcescan) 時,查詢優化器在訪問引用的表時僅考慮通過指定的索引掃描訪問路徑。可以帶索引提示 INDEX(0) 指定 FORCESCAN,以強制對基表執行表掃描操作。
--對於分割槽的表和索引,在通過查詢謂詞評估消除分割槽後應用 FORCESCAN。 這意味著掃描僅適用於剩餘分割槽而非整個表。
--forcescan 提示存在以下限制:
--不能為作為 INSERT、UPDATE 或 DELETE 語句的目標的表指定該提示。
--該提示不能與一個以上的索引提示一起使用。
--該提示阻止優化器考慮表的任何空間或 XML 索引。
--不能為遠端資料來源指定該提示。
--該提示不能與 FORCESEEK 提示一起指定。

--holdlock
--等同於SERIALIZABLE。
--forceseek僅應用於那些為其指定了forceseek的表或檢視,並且僅在使用了forceseek的語句定義的事務的持續時間內應用。forceseek不能被用於包含 FOR BROWSE 選項的 SELECT 語句。

--nolock
--等同於READUNCOMMITTED。

--nowait
--指示資料庫引擎在遇到表的鎖時,立即返回一條訊息。
--nowait等同於將特定表的 SET LOCK_TIMEOUT 值指定為 0。 當TABLOCK提示也包含在內時,NOWAIT提示不起作用。 若要在使用TABLOCK提示時終止查詢而不等待,請改為在查詢前加上SETLOCK_TIMEOUT 0;。

--paglock
--在通常行或鍵採用單個鎖的地方,或者通常採用單個表鎖的地方,請採用頁鎖。
--預設情況下,請使用與操作相對應的鎖模式。 在從SNAPSHOT 隔離級別操作的事務中指定時,除非將PAGLOCK與需要鎖的其他表提示(例如,UPDLOCK 和 HOLDLOCK)組合,否則不會取得頁鎖。

--readcommited
--指定讀操作使用鎖定或行版本控制來遵循有關 READ COMMITTED隔離級別的規則。
--如果 READ_COMMITTED_SNAPSHOT 資料庫選項為OFF,資料庫引擎會在讀取資料時獲取共享鎖,在讀操作完成後釋放這些鎖。
--如果資料庫選項 READ_COMMITTED_SNAPSHOT 為ON,則資料庫引擎不獲取鎖,並使用行版本控制。

--readcommitedlock
--指定讀操作使用鎖定來遵循有關READ COMMITTED隔離級別的規則。 無論READ_COMMITTED_SNAPSHOT資料庫選項的設定如何, 資料庫引擎都將在讀取資料時獲取共享鎖,在讀操作完成後釋放這些鎖。
--不能對 INSERT 語句的目標表指定此提示;將返回錯誤 4140。

--readpast
--指定資料庫引擎不讀取由其他事務鎖定的行。
--如果指定READPAST,則跳過行級鎖,但不跳過頁級鎖。 也就是說, 資料庫引擎將跳過這些行,而不是阻塞當前事務直到鎖被釋放。
--可為 UPDATE 或 DELETE 語句中以及 FROM 子句中引用的任何表指定 READPAST。 如果 READPAST 是在 UPDATE 語句中指定的,則僅當讀取資料以標識要更新的記錄時才應用 READPAST,而不考慮語句中指定 READPAST 的位置。
--不能為INSERT語句的 INTO 子句中的表指定 READPAST。 讀取外來鍵或索引檢視或者修改輔助索引時,使用 READPAST 的更新或刪除操作可能發生阻塞。
--僅可在運行於 READ COMMITTED 或 REPEATABLE READ 隔離級別的事務中指定 READPAST。 在從 SNAPSHOT 隔離級別操作的事務中指定時,READPAST 必須與需要鎖的其他表提示(例如,UPDLOCK 和 HOLDLOCK)組合。
--當 READ_COMMITTED_SNAPSHOT 資料庫選項設定為 ON 並且滿足以下條件之一時,無法指定 READPAST 表提示:
--會話的事務隔離級別為 READ COMMITTED。
--查詢中也指定了 READCOMMITTED 表提示。
--若要在上述情況下指定 READPAST 提示,請刪除 READCOMMITTED 表提示(如果存在),然後在查詢中包括 READCOMMITTEDLOCK 表提示。

--readuncommitted
--指定允許髒讀。 不釋出共享鎖來阻止其他事務修改當前事務讀取的資料,其他事務設定的排他鎖不會阻礙當前事務讀取鎖定資料。
--允許髒讀可能產生較多的併發操作,但其代價是讀取以後會被其他事務回滾的資料修改。 這可能會使您的事務出錯,向用戶顯示從未提交過的資料,或者導致使用者兩次看到記錄(或根本看不到記錄)。
--READUNCOMMITTED 和 NOLOCK 提示僅適用於資料鎖。 所有查詢(包括那些帶有 READUNCOMMITTED 和 NOLOCK 提示的查詢)都會在編譯和執行過程中獲取 Sch-S(架構穩定性)鎖。 因此,當併發事務持有表的 Sch-M(架構修改)鎖時,將阻塞查詢。
--例如,資料定義語言 (DDL) 操作在修改表的架構資訊之前獲取 Sch-M 鎖。 所有併發查詢(包括那些使用 READUNCOMMITTED 或 NOLOCK 提示執行的查詢)都會在嘗試獲取 Sch-S 鎖時被阻塞。 相反,持有 Sch-S 鎖的查詢將阻塞嘗試獲取 Sch-M 鎖的併發事務。
--不能為通過插入、更新或刪除操作修改過的表指定 READUNCOMMITTED 和 NOLOCK。 SQL Server 查詢優化器忽略 FROM 子句中應用於 UPDATE 或 DELETE 語句的目標表的 READUNCOMMITTED 和 NOLOCK 提示。
--可以通過使用以下任意一種方法,在保護事務避免對未提交的資料修改進行髒讀的同時最大程度地減少鎖爭用:
--READ COMMITTED 隔離級別,其中 READ_COMMITTED_SNAPSHOT 資料庫選項設定為 ON。
--SNAPSHOT 隔離級別。

--repeatableread
--指定事務在REPEATABLE READ 隔離級別執行時,使用相同的鎖定語義執行一次掃描。

--rowlock
--指定通常採用頁鎖或表鎖時,採用行鎖。 在從 SNAPSHOT 隔離級別操作的事務中指定時,除非將 ROWLOCK 與需要鎖的其他表提示(例如,UPDLOCK 和 HOLDLOCK)組合,否則不會取得行鎖。

--serializable
--等同於HOLDLOCK。保持共享鎖直到事務完成,使共享鎖更具有限制性;而不是無論事務是否完成,都在不再需要所需表或資料頁時立即釋放共享鎖。 執行掃描時所用的語義與在 SERIALIZABLE 隔離級別執行的事務的語義相同。

--snapshot
--適用範圍: SQL Server 2014 (12.x) 到 SQL Server 2017。
--記憶體優化表在SNAPSHOT隔離下訪問。 SNAPSHOT只能用於記憶體優化表 (不能用於基於磁碟的表)。

--spatial_window_max_cells=integer
--適用範圍: SQL Server 2012 (11.x) 到 SQL Server 2017。
--指定在分割 geometry 或 geography 物件時使用的最大單元格數。 number 是介於 1 和 8192 之間的值。
--通過使用此選項,可以在主要和輔助篩選器執行時間之間權衡效能以微調查詢執行時間。 較大的數字將減少輔助篩選器執行時間,但會增加主要篩選器執行時間,而較小的數字恰相反。
--對於較密的空間資料,較大的數字通過為主要篩選器提供更好的近似值並減少輔助篩選器執行時間,從而縮短了執行時間。 對於較稀疏的資料,較小的數字將減少主要篩選器執行時間。
--此選項適用於手動和自動網格分割。

--tablock
--指定在表級別應用獲取的鎖。 獲取的鎖型別取決於正在執行的語句。 例如,SELECT 語句可能獲取一個共享鎖。 通過指定 TABLOCK,將該共享鎖應用到整個表而非在行或頁級別應用。 如果同時指定了 HOLDLOCK,則會一直持有表鎖,直至事務結束。
--在使用 INSERT INTO <target_table> SELECT <columns> FROM <source_table> 語句將資料匯入某個堆時,可通過為目標表指定 TABLOCK 提示,實現語句的優化日誌記錄和鎖定。 此外,資料庫的恢復模式必須設定為簡單或大容量日誌模式。
--在與 OPENROWSET BULK 行集提供程式一起使用以將資料匯入表時,TABLOCK 允許多個客戶端使用優化日誌記錄和鎖定,以併發方式將資料載入到目標表中。

--tablockx
--指定對錶採用排他鎖。

--updlock
--指定採用更新鎖並保持到事務完成。UPDLOCK 僅對行級別或頁級別的讀操作採用更新鎖。 如果將 UPDLOCK 與 TABLOCK 組合使用或出於一些其他原因採用表級鎖,將採用排他 (X) 鎖。
--指定 UPDLOCK 時,忽略 READCOMMITTED 和 READCOMMITTEDLOCK 隔離級別提示。 例如,如果將會話的隔離級別設定為 SERIALIZABLE 且查詢指定 (UPDLOCK, READCOMMITTED),則忽略 READCOMMITTED 提示且使用 SERIALIZABLE 隔離級別執行事務。

--xlock
--指定採用排他鎖並保持到事務完成。 如果同時指定了 ROWLOCK, PAGLOCK 或 TABLOCK,則排他鎖將應用於相應的粒度級別。

示例:

select * from test1 with(tablockx);

檢視資料庫所有鎖:

exec sp_lock;

刪除表鎖:

declare @spid int;
Set @spid = 1; --鎖表程序
declare @sql varchar(1000) ;
set @sql='kill '+cast(@spid as varchar) ;
exec(@sql) ;