背景:目前參與的乙個專案,我發現乙個問題,就是大家在寫查詢時,為了效能,往往會在表後面加乙個nolock,或者是with(nolock),其目的就是查詢是不鎖定表,從而達到提高查詢速度的目的。這點可能很多朋友在做開發時都會遇到,不過如果說系統中的每個查詢語句中的表都加上nolock,您是否同意這麼做呢?在回答這個問題前我先說下幾個問題:
什麼是併發訪問:同一時間有多個使用者訪問同一資源,併發使用者中如果有使用者對資源做了修改,此時就會對其它使用者產生某些不利的影響,例如:
1:髒讀,乙個使用者對乙個資源做了修改,此時另外乙個使用者正好讀取了這條被修改的記錄,然後,第乙個使用者放棄修改,資料回到修改之前,這兩個不同的結果就是髒讀。
2:不可重複讀,乙個使用者的乙個操作是乙個事務,這個事務分兩次讀取同一條記錄,如果第一次讀取後,有另外使用者修改了這個資料,然後第二次讀取的資料正好是其它使用者修改的資料,這樣造成兩次讀取的記錄不同,如果事務中鎖定這條記錄就可以避免。
3:幻讀,指使用者讀取一批記錄的情況,使用者兩次查詢同一條件的一批記錄,第一次查詢後,有其它使用者對這批資料做了修改,方法可能是修改,刪除,新增,第二次查詢時,會發現第一次查詢的記錄條目有的不在第二次查詢結果中,或者是第二次查詢的條目不在第一次查詢的內容中。
為什麼會在查詢的表後面加nolock標識?為了避免併發訪問產生的不利影響,sql server有兩種併發訪問的控制機制:鎖、行版本控制,表後面加nolock是解決併發訪問的方案之一。
1> 鎖,每個事務對所依賴的資源會請求不同型別的鎖,它可以阻止其他事務以某種可能會導致事務請求鎖出錯的方式修改資源。當事務不再依賴鎖定的資源時,鎖將被釋放。
鎖的型別:1:表型別:鎖定整個表;2:行型別:鎖定某個行;3:檔案型別:鎖定某個資料庫檔案;4:資料庫型別:鎖定整個資料庫;5:頁型別:鎖定8k為單位的資料庫頁。
鎖的分類還有一種分法,就是按使用者和資料庫物件來分:
1). 從資料庫系統的角度來看:分為獨佔鎖(即排它鎖),共享鎖和更新鎖
1:共享 (s) :用於不更改或不更新資料的操作(唯讀操作),一般常見的例如select語句。
2:更新 (u) :用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。
3:排它 (x) :用於資料修改操作,例如 insert、update 或 delete。確保不會同時同一資源進行多重更新。
2). 從程式設計師的角度看:分為樂觀鎖和悲觀鎖。
1:樂觀鎖:完全依靠資料庫來管理鎖的工作。
2:悲觀鎖:程式設計師自己管理資料或物件上的鎖處理。
一般程式設計師一看到什麼鎖之類,覺的特別複雜,對專業的dba當然是入門級知識了。可喜的是程式設計師不用去設定,控制這些鎖,sqlserver通過設定事務的隔離級別自動管理鎖的設定和控制。鎖管理器通過查詢分析器分析待執行的sql語句,來判斷語句將會訪問哪些資源,進行什麼操作,然後結合設定的隔離級別自動分配管理需要用到的鎖。
2>:行版本控制:當啟用了基於行版本控制的隔離級別時,資料庫引擎 將維護修改的每一行的版本。應用程式可以指定事務使用行版本檢視事務或查詢開始時存在的資料,而不是使用鎖保護所有讀取。通過使用行版本控制,讀取操作阻止其他事務的可能性將大大降低。也就是相當於針對所有的表在查詢時都會加上nolock,同樣會產生髒讀的現象,但差別在於在乙個統一管理的地方。說到了基於行版本控制的隔離級別,這裡有必要說下隔離級別的概念。
隔離級別的用處:控制鎖的應用,即什麼場景應用什麼樣的鎖機制。
最終目的:解決併發處理帶來的種種問題。
隔離級別的分類:
1:未提交讀,隔離事務的最低級別,只能保證不讀取物理上損壞的資料;
2:已提交讀,資料庫引擎的缺省級;
3:可重複讀;
4:可序列化;隔離事務的最高端別,事務之間完全隔離。
小結:nolock 語句執行時不發出共享鎖,允許髒讀 ,等於 read uncommitted事務隔離級別 。nolock確實在查詢時能提高速度,但它並不是沒有缺點的,起碼它會引起髒讀。
nolock的使用場景(個人觀點):
1:資料量特別大的表,犧牲資料安全性來提公升效能是可以考慮的;
2:允許出現髒讀現象的業務邏輯,反之一些資料完整性要求比較嚴格的場景就不合適了,像金融方面等。
3:資料不經常修改的表,這樣會省於鎖定表的時間來大大加快查詢速度。
綜上所述,如果在專案中的每個查詢的表後面都加nolock,這種做法並不科學,起碼特別費時間,不如行版本控制來的直接有效。而且會存在不可預期的技術問題。應該有選擇性的挑選最適合的表來放棄共享鎖的使用。
最後說下nolock和with(nolock)的幾個小區別:
1:sql05中的同義詞,只支援with(nolock);
2:with(nolock)的寫法非常容易再指定索引。
mysql 查詢在乙個表而不在另乙個表中的資料
a b兩表,找出id欄位中,存在a表,但是不存在b表的資料。a表總共13w資料,去重後大約3w條資料,b表有2w條資料 方法一使用 not in 容易理解,效率低 執行時間為 1.395秒 select distinct a.id from a where a.id not in select id...
c 成員函式後面加乙個冒號的含義
int a 10 char b r inta 10 charb r 但是括號賦值只能在變數定義並初始化中,不能用在變數定義之後再賦值。有的資料成員需要在建構函式調入之後 函式體執行之前,就進行初始化,比如引用資料成員 常量資料成員 物件資料成員。冒號初始化是在給資料成員分配記憶體空間時 進入函式體之...
如何智慧型地在每個數字中間加乙個逗號
頭尾部都沒有 符號,用c語言實現。我感覺用if感覺太複雜了,有沒有更簡單的?例如 輸入 a 6 輸出 1,2,3,4,5,6 下面是 穀雨同學 的回答,挺值得回味的 include intmain void i for i 0 i 6 i return0 上面回答中,利用了字元指標的偏移。機智地去除...