這涉及到數(shù)據(jù)庫中,鎖的概念

創(chuàng)新互聯(lián)公司是一家專注于做網(wǎng)站、網(wǎng)站設(shè)計與策劃設(shè)計,南川網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:南川等地區(qū)。南川做網(wǎng)站價格咨詢:18980820575
首先,SQL Server更強調(diào)由系統(tǒng)來管理鎖。在用戶有SQL請求時,系統(tǒng)分析請求,自動在滿足鎖定條件和系統(tǒng)性能之間為數(shù)據(jù)庫加上適當(dāng)?shù)逆i,同時系統(tǒng)在運行期間常常自動進行優(yōu)化處理,實行動態(tài)加鎖。也就是說,你的擔(dān)心是不必要的,SQLServer可以保證這種情況基本不會出現(xiàn).如果特殊情況下,需要你手動出來,請參考下面文檔。
一. 為什么要引入鎖
多個用戶同時對數(shù)據(jù)庫的并發(fā)操作時會帶來以下數(shù)據(jù)不一致的問題:
丟失更新
A,B兩個用戶讀同一數(shù)據(jù)并進行修改,其中一個用戶的修改結(jié)果破壞了另一個修改的結(jié)果,比如訂票系統(tǒng)
臟讀
A用戶修改了數(shù)據(jù),隨后B用戶又讀出該數(shù)據(jù),但A用戶因為某些原因取消了對數(shù)據(jù)的修改,數(shù)據(jù)恢復(fù)原值,此時B得到的數(shù)據(jù)就與數(shù)據(jù)庫內(nèi)的數(shù)據(jù)產(chǎn)生了不一致
不可重復(fù)讀
A用戶讀取數(shù)據(jù),隨后B用戶讀出該數(shù)據(jù)并修改,此時A用戶再讀取數(shù)據(jù)時發(fā)現(xiàn)前后兩次的值不一致
并發(fā)控制的主要方法是封鎖,鎖就是在一段時間內(nèi)禁止用戶做某些操作以避免產(chǎn)生數(shù)據(jù)不一致
二 鎖的分類
鎖的類別有兩種分法:
1. 從數(shù)據(jù)庫系統(tǒng)的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖
MS-SQL Server 使用以下資源鎖模式。
鎖模式 描述
共享 (S) 用于不更改或不更新數(shù)據(jù)的操作(只讀操作),如 SELECT 語句。
更新 (U) 用于可更新的資源中。防止當(dāng)多個會話在讀取、鎖定以及隨后可能進行的資源更新時發(fā)生常見形式的死鎖。
排它 (X) 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。
意向鎖 用于建立鎖的層次結(jié)構(gòu)。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
架構(gòu)鎖 在執(zhí)行依賴于表架構(gòu)的操作時使用。架構(gòu)鎖的類型為:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。
大容量更新 (BU) 向表中大容量復(fù)制數(shù)據(jù)并指定了 TABLOCK 提示時使用。
共享鎖
共享 (S) 鎖允許并發(fā)事務(wù)讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務(wù)都不能修改數(shù)據(jù)。一旦已經(jīng)讀取數(shù)據(jù),便立即釋放資源上的共享 (S) 鎖,除非將事務(wù)隔離級別設(shè)置為可重復(fù)讀或更高級別,或者在事務(wù)生存周期內(nèi)用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務(wù)組成,此事務(wù)讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然后修改行,此操作要求鎖轉(zhuǎn)換為排它 (X) 鎖。如果兩個事務(wù)獲得了資源上的共享模式鎖,然后試圖同時更新數(shù)據(jù),則一個事務(wù)嘗試將鎖轉(zhuǎn)換為排它 (X) 鎖。共享模式到排它鎖的轉(zhuǎn)換必須等待一段時間,因為一個事務(wù)的排它鎖與其它事務(wù)的共享模式鎖不兼容;發(fā)生鎖等待。第二個事務(wù)試圖獲取排它 (X) 鎖以進行更新。由于兩個事務(wù)都要轉(zhuǎn)換為排它 (X) 鎖,并且每個事務(wù)都等待另一個事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。
若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務(wù)可以獲得資源的更新 (U) 鎖。如果事務(wù)修改資源,則更新 (U) 鎖轉(zhuǎn)換為排它 (X) 鎖。否則,鎖轉(zhuǎn)換為共享鎖。
排它鎖
排它 (X) 鎖可以防止并發(fā)事務(wù)對資源進行訪問。其它事務(wù)不能讀取或修改排它 (X) 鎖鎖定的數(shù)據(jù)。
意向鎖
意向鎖表示 SQL Server 需要在層次結(jié)構(gòu)中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務(wù)打算在表中的頁或行上放置共享 (S) 鎖。在表級設(shè)置意向鎖可防止另一個事務(wù)隨后在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務(wù)是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務(wù)是否可以鎖定整個表。
意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
鎖模式 描述
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的部分(而不是全部)底層資源。
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務(wù)的意向是修改層次結(jié)構(gòu)中的部分(而不是全部)底層資源。IX 是 IS 的超集。
與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的全部底層資源并修改部分(而不是全部)底層資源。允許頂層資源上的并發(fā) IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許并發(fā) IS 鎖),在當(dāng)前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內(nèi)只能有一個 SIX 鎖,以防止其它事務(wù)對資源進行更新,但是其它事務(wù)可以通過獲取表級的 IS 鎖來讀取層次結(jié)構(gòu)中的底層資源。
獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執(zhí)行數(shù)據(jù)更新命令時,SQL Server會自動使用獨占鎖。當(dāng)對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執(zhí)行Select時,SQL Server會對對象加共享鎖。
更新鎖:當(dāng)SQL Server準(zhǔn)備更新數(shù)據(jù)時,它首先對數(shù)據(jù)對象作更新鎖鎖定,這樣數(shù)據(jù)將不能被修改,但可以讀取。等到SQL Server確定要進行更新數(shù)據(jù)操作時,他會自動將更新鎖換為獨占鎖,當(dāng)對象上有其他鎖存在時,無法對其加更新鎖。
2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠數(shù)據(jù)庫來管理鎖的工作。
悲觀鎖:程序員自己管理數(shù)據(jù)或?qū)ο笊系逆i處理。
MS-SQLSERVER 使用鎖在多個同時在數(shù)據(jù)庫內(nèi)執(zhí)行修改的用戶間實現(xiàn)悲觀并發(fā)控制
三 鎖的粒度
鎖粒度是被封鎖目標(biāo)的大小,封鎖粒度小則并發(fā)性高,但開銷大,封鎖粒度大則并發(fā)性低但開銷小
SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或數(shù)據(jù)庫獲取鎖
資源 描述
RID 行標(biāo)識符。用于單獨鎖定表中的一行。
鍵 索引中的行鎖。用于保護可串行事務(wù)中的鍵范圍。
頁 8 千字節(jié) (KB) 的數(shù)據(jù)頁或索引頁。
擴展盤區(qū) 相鄰的八個數(shù)據(jù)頁或索引頁構(gòu)成的一組。
表 包括所有數(shù)據(jù)和索引在內(nèi)的整個表。
DB 數(shù)據(jù)庫。
四 鎖定時間的長短
鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。
用于保護讀取操作的共享鎖的保持時間取決于事務(wù)隔離級別。采用 READ COMMITTED 的默認(rèn)事務(wù)隔離級別時,只在讀取頁的期間內(nèi)控制共享鎖。在掃描中,直到在掃描內(nèi)的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務(wù)隔離級別設(shè)置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務(wù)結(jié)束才釋放鎖。
根據(jù)為游標(biāo)設(shè)置的并發(fā)選項,游標(biāo)可以獲取共享模式的滾動鎖以保護提取。當(dāng)需要滾動鎖時,直到下一次提取或關(guān)閉游標(biāo)(以先發(fā)生者為準(zhǔn))時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務(wù)結(jié)束才釋放滾動鎖。
用于保護更新的排它鎖將直到事務(wù)結(jié)束才釋放。
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:
將沖突鎖釋放而且連接獲取了所請求的鎖。
連接的超時間隔已到期。默認(rèn)情況下沒有超時間隔,但是一些應(yīng)用程序設(shè)置超時間隔以防止無限期等待
五 SQL Server 中鎖的自定義
1 處理死鎖和設(shè)置死鎖優(yōu)先級
死鎖就是多個用戶申請不同封鎖,由于申請者均擁有一部分封鎖權(quán)而又等待其他用戶擁有的部分封鎖而引起的無休止的等待
可以使用SET DEADLOCK_PRIORITY控制在發(fā)生死鎖情況時會話的反應(yīng)方式。如果兩個進程都鎖定數(shù)據(jù),并且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發(fā)生死鎖情況。
2 處理超時和設(shè)置鎖超時持續(xù)時間。
@@LOCK_TIMEOUT 返回當(dāng)前會話的當(dāng)前鎖超時設(shè)置,單位為毫秒
SET LOCK_TIMEOUT 設(shè)置允許應(yīng)用程序設(shè)置語句等待阻塞資源的最長時間。當(dāng)語句等待的時間大于 LOCK_TIMEOUT 設(shè)置時,系統(tǒng)將自動取消阻塞的語句,并給應(yīng)用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息
示例
下例將鎖超時期限設(shè)置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800
3) 設(shè)置事務(wù)隔離級別。
4 ) 對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。
5) 配置索引的鎖定粒度
可以使用 sp_indexoption 系統(tǒng)存儲過程來設(shè)置用于索引的鎖定粒度
六 查看鎖的信息
1 執(zhí)行 EXEC SP_LOCK 報告有關(guān)鎖的信息
2 查詢分析器中按Ctrl+2可以看到鎖的信息
七 使用注意事項
如何避免死鎖
1 使用事務(wù)時,盡量縮短事務(wù)的邏輯處理過程,及早提交或回滾事務(wù);
2 設(shè)置死鎖超時參數(shù)為合理范圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優(yōu)化程序,檢查并避免死鎖現(xiàn)象出現(xiàn);
4 .對所有的腳本和SP都要仔細(xì)測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL SERVER事務(wù)的默認(rèn)級別。不推薦強行加鎖
解決問題 如何對行 表 數(shù)據(jù)庫加鎖
八 幾個有關(guān)鎖的問題
1 如何鎖一個表的某一行
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM table ROWLOCK WHERE id = 1
2 鎖定數(shù)據(jù)庫的一個表
SELECT * FROM table WITH (HOLDLOCK)
加鎖語句:
sybase:
update 表 set col1=col1 where 1=0 ;
MSSQL:
select col1 from 表 (tablockx) where 1=0 ;
oracle:
LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖后其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖
幾個例子幫助大家加深印象
設(shè)table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
1)排它鎖
新建兩個連接
在第一個連接中執(zhí)行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
select * from table1
where B='b2'
commit tran
若同時執(zhí)行上述兩個語句,則select查詢必須等待update執(zhí)行完畢才能執(zhí)行即要等待30秒
2)共享鎖
在第一個連接中執(zhí)行以下語句
begin tran
select * from table1 holdlock -holdlock人為加鎖
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran
若同時執(zhí)行上述兩個語句,則第二個連接中的select查詢可以執(zhí)行
而update必須等待第一個事務(wù)釋放共享鎖轉(zhuǎn)為排它鎖后才能執(zhí)行 即要等待30秒
3)死鎖
增設(shè)table2(D,E)
D E
d1 e1
d2 e2
在第一個連接中執(zhí)行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30'
update table2
set D='d5'
where E='e1'
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
update table2
set D='d5'
where E='e1'
waitfor delay '00:00:10'
update table1
set A='aa'
where B='b2'
commit tran
同時執(zhí)行,系統(tǒng)會檢測出死鎖,并中止進程
補充一點:
Sql Server2000支持的表級鎖定提示
HOLDLOCK 持有共享鎖,直到整個事務(wù)完成,應(yīng)該在被鎖對象不需要時立即釋放,等于SERIALIZABLE事務(wù)隔離級別
NOLOCK 語句執(zhí)行時不發(fā)出共享鎖,允許臟讀 ,等于 READ UNCOMMITTED事務(wù)隔離級別
PAGLOCK 在使用一個表鎖的地方用多個頁鎖
READPAST 讓sql server跳過任何鎖定行,執(zhí)行事務(wù),適用于READ UNCOMMITTED事務(wù)隔離級別只跳過RID鎖,不跳過頁,區(qū)域和表鎖
ROWLOCK 強制使用行鎖
TABLOCKX 強制使用獨占表級鎖,這個鎖在事務(wù)期間阻止任何其他事務(wù)使用這個表
UPLOCK 強制在讀表時使用更新而不用共享鎖
應(yīng)用程序鎖:
應(yīng)用程序鎖就是客戶端代碼生成的鎖,而不是sql server本身生成的鎖
處理應(yīng)用程序鎖的兩個過程
sp_getapplock 鎖定應(yīng)用程序資源
sp_releaseapplock 為應(yīng)用程序資源解鎖
注意: 鎖定數(shù)據(jù)庫的一個表的區(qū)別
SELECT * FROM table WITH (HOLDLOCK) 其他事務(wù)可以讀取表,但不能更新刪除
SELECT * FROM table WITH (TABLOCKX) 其他事務(wù)不能讀取表,更新和刪除
在良好的數(shù)據(jù)庫設(shè)計基礎(chǔ)上,能有效地使用索引是SQL Server取得高性能的基礎(chǔ),SQL Server采用基于代價的優(yōu)化模型,它對每一個提交的有關(guān)表的查詢,決定是否使用索引或用哪一個索引。因為查詢執(zhí)行的大部分開銷是磁盤I/O,使用索引提高性能的一個主要目標(biāo)是避免全表掃描,因為全表掃描需要從磁盤上讀表的每一個數(shù)據(jù)頁,如果有索引指向數(shù)據(jù)值,則查詢只需讀幾次磁盤就可以了。
所以如果建立了合理的索引,優(yōu)化器就能利用索引加速數(shù)據(jù)的查詢過程。但是,索引并不總是提高系統(tǒng)的性能,在增、刪、改操作中索引的存在會增加一定的工作量,因此,在適當(dāng)?shù)牡胤皆黾舆m當(dāng)?shù)乃饕牟缓侠淼牡胤絼h除次優(yōu)的索引,將有助于優(yōu)化那些性能較差的SQL Server應(yīng)用。實踐表明,合理的索引設(shè)計是建立在對各種查詢的分析和預(yù)測上的,只有正確地使索引與程序結(jié)合起來,才能產(chǎn)生最佳的優(yōu)化方案。本文就SQL Server索引的性能問題進行了一些分析和實踐。
一、聚簇索引(clustered indexes)的使用
聚簇索引是一種對磁盤上實際數(shù)據(jù)重新組織以按指定的一個或多個列的值排序。由于聚簇索引的索引頁面指針指向數(shù)據(jù)頁面,所以使用聚簇索引查找數(shù)據(jù)幾乎總是比使用非聚簇索引快。每張表只能建一個聚簇索引,并且建聚簇索引需要至少相當(dāng)該表120%的附加空間,以存放該表的副本和索引中間頁。建立聚簇索引的思想是:
1、大多數(shù)表都應(yīng)該有聚簇索引或使用分區(qū)來降低對表尾頁的競爭,在一個高事務(wù)的環(huán)境中,對最后一頁的封鎖嚴(yán)重影響系統(tǒng)的吞吐量。
2、在聚簇索引下,數(shù)據(jù)在物理上按順序排在數(shù)據(jù)頁上,重復(fù)值也排在一起,因而在那些包含范圍檢查(between、、=、、=)或使用group by或order by的查詢時,一旦找到具有范圍中第一個鍵值的行,具有后續(xù)索引值的行保證物理上毗連在一起而不必進一步搜索,避免了大范圍掃描,可以大大提高查詢速度。
3、在一個頻繁發(fā)生插入操作的表上建立聚簇索引時,不要建在具有單調(diào)上升值的列(如IDENTITY)上,否則會經(jīng)常引起封鎖沖突。
4、在聚簇索引中不要包含經(jīng)常修改的列,因為碼值修改后,數(shù)據(jù)行必須移動到新的位置。
5、選擇聚簇索引應(yīng)基于where子句和連接操作的類型。
聚簇索引的侯選列是:
1、主鍵列,該列在where子句中使用并且插入是隨機的。
2、按范圍存取的列,如pri_order 100 and pri_order 200。
3、在group by或order by中使用的列。
4、不經(jīng)常修改的列。
5、在連接操作中使用的列。
二、非聚簇索引(nonclustered indexes)的使用
SQL Server缺省情況下建立的索引是非聚簇索引,由于非聚簇索引不重新組織表中的數(shù)據(jù),而是對每一行存儲索引列值并用一個指針指向數(shù)據(jù)所在的頁面。換句話說非聚簇索引具有在索引結(jié)構(gòu)和數(shù)據(jù)本身之間的一個額外級。一個表如果沒有聚簇索引時,可有250個非聚簇索引。每個非聚簇索引提供訪問數(shù)據(jù)的不同排序順序。在建立非聚簇索引時,要權(quán)衡索引對查詢速度的加快與降低修改速度之間的利弊。另外,還要考慮這些問題:
1、索引需要使用多少空間。
2、合適的列是否穩(wěn)定。
3、索引鍵是如何選擇的,掃描效果是否更佳。
4、是否有許多重復(fù)值。
對更新頻繁的表來說,表上的非聚簇索引比聚簇索引和根本沒有索引需要更多的額外開銷。對移到新頁的每一行而言,指向該數(shù)據(jù)的每個非聚簇索引的頁級行也必須更新,有時可能還需要索引頁的分理。從一個頁面刪除數(shù)據(jù)的進程也會有類似的開銷,另外,刪除進程還必須把數(shù)據(jù)移到頁面上部,以保證數(shù)據(jù)的連續(xù)性。所以,建立非聚簇索引要非常慎重。非聚簇索引常被用在以下情況:
1、某列常用于集合函數(shù)(如Sum,....)。
2、某列常用于join,order by,group by。
3、查尋出的數(shù)據(jù)不超過表中數(shù)據(jù)量的20%。
三、覆蓋索引(covering indexes)的使用
覆蓋索引是指那些索引項中包含查尋所需要的全部信息的非聚簇索引,這種索引之所以比較快也正是因為索引頁中包含了查尋所必須的數(shù)據(jù),不需去訪問數(shù)據(jù)頁。如果非聚簇索引中包含結(jié)果數(shù)據(jù),那么它的查詢速度將快于聚簇索引。
但是由于覆蓋索引的索引項比較多,要占用比較大的空間。而且update操作會引起索引值改變。所以如果潛在的覆蓋查詢并不常用或不太關(guān)鍵,則覆蓋索引的增加反而會降低性能。
四、索引的選擇技術(shù)
p_detail是住房公積金管理系統(tǒng)中記錄個人明細(xì)的表,有890000行,觀察在不同索引下的查詢運行效果,測試在C/S環(huán)境下進行,客戶機是IBM PII350(內(nèi)存64M),服務(wù)器是DEC Alpha1000A(內(nèi)存128M),數(shù)據(jù)庫為SYBASE11.0.3。
1、 select count(*) from p_detail where
op_date’19990101’ and op_date’
19991231’ and pri_surplus1300
2、 select count(*),sum(pri_surplus1) from p_detail
where op_date’19990101’ and
pay_month between‘199908’ and’199912’
不建任何索引查詢1 1分15秒
查詢2 1分7秒
在op_date上建非聚簇索引查詢1 57秒
查詢2 57秒
在op_date上建聚簇索引查詢1 1秒
查詢2 52秒
在pay_month、op_date、pri_surplus1上建索引查詢1 34秒
查詢2 1秒
在op_date、pay_month、pri_surplus1上建索引查詢1 1秒
查詢2 1秒
從以上查詢效果分析,索引的有無,建立方式的不同將會導(dǎo)致不同的查詢效果,選擇什么樣的索引基于用戶對數(shù)據(jù)的查詢條件,這些條件體現(xiàn)于where從句和join表達(dá)式中。一般來說建立索引的思路是:
(1)主鍵時常作為where子句的條件,應(yīng)在表的主鍵列上建立聚簇索引,尤其當(dāng)經(jīng)常用它作為連接的時候。
(2)有大量重復(fù)值且經(jīng)常有范圍查詢和排序、分組發(fā)生的列,或者非常頻繁地被訪問的列,可考慮建立聚簇索引。
(3)經(jīng)常同時存取多列,且每列都含有重復(fù)值可考慮建立復(fù)合索引來覆蓋一個或一組查詢,并把查詢引用最頻繁的列作為前導(dǎo)列,如果可能盡量使關(guān)鍵查詢形成覆蓋查詢。
(4)如果知道索引鍵的所有值都是唯一的,那么確保把索引定義成唯一索引。
(5)在一個經(jīng)常做插入操作的表上建索引時,使用fillfactor(填充因子)來減少頁分裂,同時提高并發(fā)度降低死鎖的發(fā)生。如果在只讀表上建索引,則可以把fillfactor置為100。
(6)在選擇索引鍵時,設(shè)法選擇那些采用小數(shù)據(jù)類型的列作為鍵以使每個索引頁能夠容納盡可能多的索引鍵和指針,通過這種方式,可使一個查詢必須遍歷的索引頁面降到最小。此外,盡可能地使用整數(shù)為鍵值,因為它能夠提供比任何數(shù)據(jù)類型都快的訪問速度。
五、索引的維護
上面講到,某些不合適的索引影響到SQL Server的性能,隨著應(yīng)用系統(tǒng)的運行,數(shù)據(jù)不斷地發(fā)生變化,當(dāng)數(shù)據(jù)變化達(dá)到某一個程度時將會影響到索引的使用。這時需要用戶自己來維護索引。索引的維護包括:
1、重建索引
隨著數(shù)據(jù)行的插入、刪除和數(shù)據(jù)頁的分裂,有些索引頁可能只包含幾頁數(shù)據(jù),另外應(yīng)用在執(zhí)行大塊I/O的時候,重建非聚簇索引可以降低分片,維護大塊I/O的效率。重建索引實際上是重新組織B-樹空間。在下面情況下需要重建索引:
(1)數(shù)據(jù)和使用模式大幅度變化。
(2)排序的順序發(fā)生改變。
(3)要進行大量插入操作或已經(jīng)完成。
(4)使用大塊I/O的查詢的磁盤讀次數(shù)比預(yù)料的要多。
(5)由于大量數(shù)據(jù)修改,使得數(shù)據(jù)頁和索引頁沒有充分使用而導(dǎo)致空間的使用超出估算。
(6)dbcc檢查出索引有問題。
當(dāng)重建聚簇索引時,這張表的所有非聚簇索引將被重建。
2、索引統(tǒng)計信息的更新
當(dāng)在一個包含數(shù)據(jù)的表上創(chuàng)建索引的時候,SQL Server會創(chuàng)建分布數(shù)據(jù)頁來存放有關(guān)索引的兩種統(tǒng)計信息:分布表和密度表。優(yōu)化器利用這個頁來判斷該索引對某個特定查詢是否有用。但這個統(tǒng)計信息并不動態(tài)地重新計算。這意味著,當(dāng)表的數(shù)據(jù)改變之后,統(tǒng)計信息有可能是過時的,從而影響優(yōu)化器追求最有工作的目標(biāo)。因此,在下面情況下應(yīng)該運行update statistics命令:
(1)數(shù)據(jù)行的插入和刪除修改了數(shù)據(jù)的分布。
(2)對用truncate table刪除數(shù)據(jù)的表上增加數(shù)據(jù)行。
(3)修改索引列的值。
六、結(jié)束語
實踐表明,不恰當(dāng)?shù)乃饕坏谑聼o補,反而會降低系統(tǒng)的執(zhí)行性能。因為大量的索引在插入、修改和刪除操作時比沒有索引花費更多的系統(tǒng)時間。例如下面情況下建立的索引是不恰當(dāng)?shù)模?/p>
1、在查詢中很少或從不引用的列不會受益于索引,因為索引很少或從來不必搜索基于這些列的行。
2、只有兩個或三個值的列,如男性和女性(是或否),從不會從索引中得到好處。
另外,鑒于索引加快了查詢速度,但減慢了數(shù)據(jù)更新速度的特點。可通過在一個段上建表,而在另一個段上建其非聚簇索引,而這兩段分別在單獨的物理設(shè)備上來改善操作性能。
給你個最詳細(xì)的吧 可能有你要的內(nèi)容
鎖的概述
一. 為什么要引入鎖
多個用戶同時對數(shù)據(jù)庫的并發(fā)操作時會帶來以下數(shù)據(jù)不一致的問題:
丟失更新
A,B兩個用戶讀同一數(shù)據(jù)并進行修改,其中一個用戶的修改結(jié)果破壞了另一個修改的結(jié)果,比如訂票系統(tǒng)
臟讀
A用戶修改了數(shù)據(jù),隨后B用戶又讀出該數(shù)據(jù),但A用戶因為某些原因取消了對數(shù)據(jù)的修改,數(shù)據(jù)恢復(fù)原值,此時B得到的數(shù)據(jù)就與數(shù)據(jù)庫內(nèi)的數(shù)據(jù)產(chǎn)生了不一致
不可重復(fù)讀
A用戶讀取數(shù)據(jù),隨后B用戶讀出該數(shù)據(jù)并修改,此時A用戶再讀取數(shù)據(jù)時發(fā)現(xiàn)前后兩次的值不一致
并發(fā)控制的主要方法是封鎖,鎖就是在一段時間內(nèi)禁止用戶做某些操作以避免產(chǎn)生數(shù)據(jù)不一致
二 鎖的分類
鎖的類別有兩種分法:
1. 從數(shù)據(jù)庫系統(tǒng)的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖
MS-SQL Server 使用以下資源鎖模式。
鎖模式 描述
共享 (S) 用于不更改或不更新數(shù)據(jù)的操作(只讀操作),如 SELECT 語句。
更新 (U) 用于可更新的資源中。防止當(dāng)多個會話在讀取、鎖定以及隨后可能進行的資源更新時發(fā)生常見形式的死鎖。
排它 (X) 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。
意向鎖 用于建立鎖的層次結(jié)構(gòu)。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
架構(gòu)鎖 在執(zhí)行依賴于表架構(gòu)的操作時使用。架構(gòu)鎖的類型為:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。
大容量更新 (BU) 向表中大容量復(fù)制數(shù)據(jù)并指定了 TABLOCK 提示時使用。
共享鎖
共享 (S) 鎖允許并發(fā)事務(wù)讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務(wù)都不能修改數(shù)據(jù)。一旦已經(jīng)讀取數(shù)據(jù),便立即釋放資源上的共享 (S) 鎖,除非將事務(wù)隔離級別設(shè)置為可重復(fù)讀或更高級別,或者在事務(wù)生存周期內(nèi)用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務(wù)組成,此事務(wù)讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然后修改行,此操作要求鎖轉(zhuǎn)換為排它 (X) 鎖。如果兩個事務(wù)獲得了資源上的共享模式鎖,然后試圖同時更新數(shù)據(jù),則一個事務(wù)嘗試將鎖轉(zhuǎn)換為排它 (X) 鎖。共享模式到排它鎖的轉(zhuǎn)換必須等待一段時間,因為一個事務(wù)的排它鎖與其它事務(wù)的共享模式鎖不兼容;發(fā)生鎖等待。第二個事務(wù)試圖獲取排它 (X) 鎖以進行更新。由于兩個事務(wù)都要轉(zhuǎn)換為排它 (X) 鎖,并且每個事務(wù)都等待另一個事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。
若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務(wù)可以獲得資源的更新 (U) 鎖。如果事務(wù)修改資源,則更新 (U) 鎖轉(zhuǎn)換為排它 (X) 鎖。否則,鎖轉(zhuǎn)換為共享鎖。
排它鎖
排它 (X) 鎖可以防止并發(fā)事務(wù)對資源進行訪問。其它事務(wù)不能讀取或修改排它 (X) 鎖鎖定的數(shù)據(jù)。
意向鎖
意向鎖表示 SQL Server 需要在層次結(jié)構(gòu)中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務(wù)打算在表中的頁或行上放置共享 (S) 鎖。在表級設(shè)置意向鎖可防止另一個事務(wù)隨后在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務(wù)是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務(wù)是否可以鎖定整個表。
意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
鎖模式 描述
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的部分(而不是全部)底層資源。
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務(wù)的意向是修改層次結(jié)構(gòu)中的部分(而不是全部)底層資源。IX 是 IS 的超集。
與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的全部底層資源并修改部分(而不是全部)底層資源。允許頂層資源上的并發(fā) IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許并發(fā) IS 鎖),在當(dāng)前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內(nèi)只能有一個 SIX 鎖,以防止其它事務(wù)對資源進行更新,但是其它事務(wù)可以通過獲取表級的 IS 鎖來讀取層次結(jié)構(gòu)中的底層資源。
獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執(zhí)行數(shù)據(jù)更新命令時,SQL Server會自動使用獨占鎖。當(dāng)對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執(zhí)行Select時,SQL Server會對對象加共享鎖。
更新鎖:當(dāng)SQL Server準(zhǔn)備更新數(shù)據(jù)時,它首先對數(shù)據(jù)對象作更新鎖鎖定,這樣數(shù)據(jù)將不能被修改,但可以讀取。等到SQL Server確定要進行更新數(shù)據(jù)操作時,他會自動將更新鎖換為獨占鎖,當(dāng)對象上有其他鎖存在時,無法對其加更新鎖。
2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠數(shù)據(jù)庫來管理鎖的工作。
悲觀鎖:程序員自己管理數(shù)據(jù)或?qū)ο笊系逆i處理。
MS-SQLSERVER 使用鎖在多個同時在數(shù)據(jù)庫內(nèi)執(zhí)行修改的用戶間實現(xiàn)悲觀并發(fā)控制
三 鎖的粒度
鎖粒度是被封鎖目標(biāo)的大小,封鎖粒度小則并發(fā)性高,但開銷大,封鎖粒度大則并發(fā)性低但開銷小
SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或數(shù)據(jù)庫獲取鎖
資源 描述
RID 行標(biāo)識符。用于單獨鎖定表中的一行。
鍵 索引中的行鎖。用于保護可串行事務(wù)中的鍵范圍。
頁 8 千字節(jié) (KB) 的數(shù)據(jù)頁或索引頁。
擴展盤區(qū) 相鄰的八個數(shù)據(jù)頁或索引頁構(gòu)成的一組。
表 包括所有數(shù)據(jù)和索引在內(nèi)的整個表。
DB 數(shù)據(jù)庫。
四 鎖定時間的長短
鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。
用于保護讀取操作的共享鎖的保持時間取決于事務(wù)隔離級別。采用 READ COMMITTED 的默認(rèn)事務(wù)隔離級別時,只在讀取頁的期間內(nèi)控制共享鎖。在掃描中,直到在掃描內(nèi)的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務(wù)隔離級別設(shè)置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務(wù)結(jié)束才釋放鎖。
根據(jù)為游標(biāo)設(shè)置的并發(fā)選項,游標(biāo)可以獲取共享模式的滾動鎖以保護提取。當(dāng)需要滾動鎖時,直到下一次提取或關(guān)閉游標(biāo)(以先發(fā)生者為準(zhǔn))時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務(wù)結(jié)束才釋放滾動鎖。
用于保護更新的排它鎖將直到事務(wù)結(jié)束才釋放。
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:
將沖突鎖釋放而且連接獲取了所請求的鎖。
連接的超時間隔已到期。默認(rèn)情況下沒有超時間隔,但是一些應(yīng)用程序設(shè)置超時間隔以防止無限期等待
五 SQL Server 中鎖的自定義
1 處理死鎖和設(shè)置死鎖優(yōu)先級
死鎖就是多個用戶申請不同封鎖,由于申請者均擁有一部分封鎖權(quán)而又等待其他用戶擁有的部分封鎖而引起的無休止的等待
可以使用SET DEADLOCK_PRIORITY控制在發(fā)生死鎖情況時會話的反應(yīng)方式。如果兩個進程都鎖定數(shù)據(jù),并且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發(fā)生死鎖情況。
2 處理超時和設(shè)置鎖超時持續(xù)時間。
@@LOCK_TIMEOUT 返回當(dāng)前會話的當(dāng)前鎖超時設(shè)置,單位為毫秒
SET LOCK_TIMEOUT 設(shè)置允許應(yīng)用程序設(shè)置語句等待阻塞資源的最長時間。當(dāng)語句等待的時間大于 LOCK_TIMEOUT 設(shè)置時,系統(tǒng)將自動取消阻塞的語句,并給應(yīng)用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息
示例
下例將鎖超時期限設(shè)置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800
3) 設(shè)置事務(wù)隔離級別。
4 ) 對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。
5) 配置索引的鎖定粒度
可以使用 sp_indexoption 系統(tǒng)存儲過程來設(shè)置用于索引的鎖定粒度
六 查看鎖的信息
1 執(zhí)行 EXEC SP_LOCK 報告有關(guān)鎖的信息
2 查詢分析器中按Ctrl+2可以看到鎖的信息
七 使用注意事項
如何避免死鎖
1 使用事務(wù)時,盡量縮短事務(wù)的邏輯處理過程,及早提交或回滾事務(wù);
2 設(shè)置死鎖超時參數(shù)為合理范圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優(yōu)化程序,檢查并避免死鎖現(xiàn)象出現(xiàn);
4 .對所有的腳本和SP都要仔細(xì)測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL SERVER事務(wù)的默認(rèn)級別。不推薦強行加鎖
解決問題 如何對行 表 數(shù)據(jù)庫加鎖
八 幾個有關(guān)鎖的問題
1 如何鎖一個表的某一行
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM table ROWLOCK WHERE id = 1
2 鎖定數(shù)據(jù)庫的一個表
SELECT * FROM table WITH (HOLDLOCK)
加鎖語句:
sybase:
update 表 set col1=col1 where 1=0 ;
MSSQL:
select col1 from 表 (tablockx) where 1=0 ;
oracle:
LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖后其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖
幾個例子幫助大家加深印象
設(shè)table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
1)排它鎖
新建兩個連接
在第一個連接中執(zhí)行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
select * from table1
where B='b2'
commit tran
若同時執(zhí)行上述兩個語句,則select查詢必須等待update執(zhí)行完畢才能執(zhí)行即要等待30秒
2)共享鎖
在第一個連接中執(zhí)行以下語句
begin tran
select * from table1 holdlock -holdlock人為加鎖
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran
若同時執(zhí)行上述兩個語句,則第二個連接中的select查詢可以執(zhí)行
而update必須等待第一個事務(wù)釋放共享鎖轉(zhuǎn)為排它鎖后才能執(zhí)行 即要等待30秒
3)死鎖
增設(shè)table2(D,E)
D E
d1 e1
d2 e2
在第一個連接中執(zhí)行以下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30'
update table2
set D='d5'
where E='e1'
commit tran
在第二個連接中執(zhí)行以下語句
begin tran
update table2
set D='d5'
where E='e1'
waitfor delay '00:00:10'
update table1
set A='aa'
where B='b2'
commit tran
同時執(zhí)行,系統(tǒng)會檢測出死鎖,并中止進程
補充一點:
Sql Server2000支持的表級鎖定提示
HOLDLOCK 持有共享鎖,直到整個事務(wù)完成,應(yīng)該在被鎖對象不需要時立即釋放,等于SERIALIZABLE事務(wù)隔離級別
NOLOCK 語句執(zhí)行時不發(fā)出共享鎖,允許臟讀 ,等于 READ UNCOMMITTED事務(wù)隔離級別
PAGLOCK 在使用一個表鎖的地方用多個頁鎖
READPAST 讓sql server跳過任何鎖定行,執(zhí)行事務(wù),適用于READ UNCOMMITTED事務(wù)隔離級別只跳過RID鎖,不跳過頁,區(qū)域和表鎖
ROWLOCK 強制使用行鎖
TABLOCKX 強制使用獨占表級鎖,這個鎖在事務(wù)期間阻止任何其他事務(wù)使用這個表
UPLOCK 強制在讀表時使用更新而不用共享鎖
應(yīng)用程序鎖:
應(yīng)用程序鎖就是客戶端代碼生成的鎖,而不是sql server本身生成的鎖
處理應(yīng)用程序鎖的兩個過程
sp_getapplock 鎖定應(yīng)用程序資源
sp_releaseapplock 為應(yīng)用程序資源解鎖
注意: 鎖定數(shù)據(jù)庫的一個表的區(qū)別
SELECT * FROM table WITH (HOLDLOCK) 其他事務(wù)可以讀取表,但不能更新刪除
SELECT * FROM table WITH (TABLOCKX) 其他事務(wù)不能讀取表,更新和刪除
參考資料:
1.數(shù)據(jù)庫服務(wù)沒有啟動;
2.登錄時的用戶名和密碼不正確;
3.你所使用的用戶沒有登錄權(quán)限;
4.防火墻封鎖了數(shù)據(jù)庫使用的端口。
從企業(yè)管理器里刪除現(xiàn)有的連接,重新建立,輸入正確的并且是有登錄權(quán)限的用戶名稱和密碼。
鎖的概述
一. 為什么要引入鎖
多個用戶同時對數(shù)據(jù)庫的并發(fā)操作時會帶來以下數(shù)據(jù)不一致的問題:
丟失更新
A,B兩個用戶讀同一數(shù)據(jù)并進行修改,其中一個用戶的修改結(jié)果破壞了另一個修改的結(jié)果,比如訂票系統(tǒng)
臟讀
A用戶修改了數(shù)據(jù),隨后B用戶又讀出該數(shù)據(jù),但A用戶因為某些原因取消了對數(shù)據(jù)的修改,數(shù)據(jù)恢復(fù)原值,此時B得到的數(shù)據(jù)就與數(shù)據(jù)庫內(nèi)的數(shù)據(jù)產(chǎn)生了不一致
不可重復(fù)讀
A用戶讀取數(shù)據(jù),隨后B用戶讀出該數(shù)據(jù)并修改,此時A用戶再讀取數(shù)據(jù)時發(fā)現(xiàn)前后兩次的值不一致
并發(fā)控制的主要方法是封鎖,鎖就是在一段時間內(nèi)禁止用戶做某些操作以避免產(chǎn)生數(shù)據(jù)不一致
二 鎖的分類
鎖的類別有兩種分法:
1. 從數(shù)據(jù)庫系統(tǒng)的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖
MS SQL Server 使用以下資源鎖模式。
鎖模式 描述
共享 (S) 用于不更改或不更新數(shù)據(jù)的操作(只讀操作),如 SELECT 語句。
更新 (U) 用于可更新的資源中。防止當(dāng)多個會話在讀取、鎖定以及隨后可能進行的資源更新時發(fā)生常見形式的死鎖。
排它 (X) 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。
意向鎖 用于建立鎖的層次結(jié)構(gòu)。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
架構(gòu)鎖 在執(zhí)行依賴于表架構(gòu)的操作時使用。架構(gòu)鎖的類型為:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。
大容量更新 (BU) 向表中大容量復(fù)制數(shù)據(jù)并指定了 TABLOCK 提示時使用。
共享鎖
共享 (S) 鎖允許并發(fā)事務(wù)讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務(wù)都不能修改數(shù)據(jù)。一旦已經(jīng)讀取數(shù)據(jù),便立即釋放資源上的共享 (S) 鎖,除非將事務(wù)隔離級別設(shè)置為可重復(fù)讀或更高級別,或者在事務(wù)生存周期內(nèi)用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務(wù)組成,此事務(wù)讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然后修改行,此操作要求鎖轉(zhuǎn)換為排它 (X) 鎖。如果兩個事務(wù)獲得了資源上的共享模式鎖,然后試圖同時更新數(shù)據(jù),則一個事務(wù)嘗試將鎖轉(zhuǎn)換為排它 (X) 鎖。共享模式到排它鎖的轉(zhuǎn)換必須等待一段時間,因為一個事務(wù)的排它鎖與其它事務(wù)的共享模式鎖不兼容;發(fā)生鎖等待。第二個事務(wù)試圖獲取排它 (X) 鎖以進行更新。由于兩個事務(wù)都要轉(zhuǎn)換為排它 (X) 鎖,并且每個事務(wù)都等待另一個事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。
若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務(wù)可以獲得資源的更新 (U) 鎖。如果事務(wù)修改資源,則更新 (U) 鎖轉(zhuǎn)換為排它 (X) 鎖。否則,鎖轉(zhuǎn)換為共享鎖。
排它鎖
排它 (X) 鎖可以防止并發(fā)事務(wù)對資源進行訪問。其它事務(wù)不能讀取或修改排它 (X) 鎖鎖定的數(shù)據(jù)。
意向鎖
意向鎖表示 SQL Server 需要在層次結(jié)構(gòu)中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務(wù)打算在表中的頁或行上放置共享 (S) 鎖。在表級設(shè)置意向鎖可防止另一個事務(wù)隨后在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務(wù)是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務(wù)是否可以鎖定整個表。
意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
鎖模式
描述
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的部分(而不是全部)底層資源。
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務(wù)的意向是修改層次結(jié)構(gòu)中的部分(而不是全部)底層資源。IX 是 IS 的超集。與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的全部底層資源并修改部分(而不是全部)底層資源。允許頂層資源上的并發(fā) IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許并發(fā) IS 鎖),在當(dāng)前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內(nèi)只能有一個 SIX 鎖,以防止其它事務(wù)對資源進行更新,但是其它事務(wù)可以通過獲取表級的 IS 鎖來讀取層次結(jié)構(gòu)中的底層資源。
獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執(zhí)行數(shù)據(jù)更新命令時,SQL Server會自動使用獨占鎖。當(dāng)對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執(zhí)行Select時,SQL Server會對對象加共享鎖。
更新鎖:當(dāng)SQL Server準(zhǔn)備更新數(shù)據(jù)時,它首先對數(shù)據(jù)對象作更新鎖鎖定,這樣數(shù)據(jù)將不能被修改,但可以讀取。等到SQL Server確定要進行更新數(shù)據(jù)操作時,他會自動將更新鎖換為獨占鎖,當(dāng)對象上有其他鎖存在時,無法對其加更新鎖。
2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠數(shù)據(jù)庫來管理鎖的工作。
悲觀鎖:程序員自己管理數(shù)據(jù)或?qū)ο笊系逆i處理。
MS SQL Server 使用鎖在多個同時在數(shù)據(jù)庫內(nèi)執(zhí)行修改的用戶間實現(xiàn)悲觀并發(fā)控制
三 鎖的粒度
鎖粒度是被封鎖目標(biāo)的大小,封鎖粒度小則并發(fā)性高,但開銷大,封鎖粒度大則并發(fā)性低但開銷小
SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或數(shù)據(jù)庫獲取鎖
資源描述
RID 行標(biāo)識符。用于單獨鎖定表中的一行。
鍵 索引中的行鎖。用于保護可串行事務(wù)中的鍵范圍。
頁 8 千字節(jié) (KB) 的數(shù)據(jù)頁或索引頁。
擴展盤區(qū) 相鄰的八個數(shù)據(jù)頁或索引頁構(gòu)成的一組。
表 包括所有數(shù)據(jù)和索引在內(nèi)的整個表。
DB 數(shù)據(jù)庫。
四 鎖定時間的長短
鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。
用于保護讀取操作的共享鎖的保持時間取決于事務(wù)隔離級別。采用 READ COMMITTED 的默認(rèn)事務(wù)隔離級別時,只在讀取頁的期間內(nèi)控制共享鎖。在掃描中,直到在掃描內(nèi)的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務(wù)隔離級別設(shè)置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務(wù)結(jié)束才釋放鎖。
根據(jù)為游標(biāo)設(shè)置的并發(fā)選項,游標(biāo)可以獲取共享模式的滾動鎖以保護提取。當(dāng)需要滾動鎖時,直到下一次提取或關(guān)閉游標(biāo)(以先發(fā)生者為準(zhǔn))時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務(wù)結(jié)束才釋放滾動鎖。
用于保護更新的排它鎖將直到事務(wù)結(jié)束才釋放。
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:
將沖突鎖釋放而且連接獲取了所請求的鎖。
連接的超時間隔已到期。默認(rèn)情況下沒有超時間隔,但是一些應(yīng)用程序設(shè)置超時間隔以防止無限期等待
五 SQL Server 中鎖的自定義
1 處理死鎖和設(shè)置死鎖優(yōu)先級
死鎖就是多個用戶申請不同封鎖,由于申請者均擁有一部分封鎖權(quán)而又等待其他用戶擁有的部分封鎖而引起的無休止的等待可以使用SET DEADLOCK_PRIORITY控制在發(fā)生死鎖情況時會話的反應(yīng)方式。如果兩個進程都鎖定數(shù)據(jù),并且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發(fā)生死鎖情況。
2 處理超時和設(shè)置鎖超時持續(xù)時間。
@@LOCK_TIMEOUT 返回當(dāng)前會話的當(dāng)前鎖超時設(shè)置,單位為毫秒
SET LOCK_TIMEOUT 設(shè)置允許應(yīng)用程序設(shè)置語句等待阻塞資源的最長時間。當(dāng)語句等待的時間大于 LOCK_TIMEOUT 設(shè)置時,系統(tǒng)將自動取消阻塞的語句,并給應(yīng)用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息
示例
下例將鎖超時期限設(shè)置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800
3) 設(shè)置事務(wù)隔離級別。
4 ) 對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。
5) 配置索引的鎖定粒度
可以使用 sp_indexoption 系統(tǒng)存儲過程來設(shè)置用于索引的鎖定粒度
六 查看鎖的信息 1 執(zhí)行 EXEC SP_LOCK 報告有關(guān)鎖的信息
2 查詢分析器中按Ctrl+2可以看到鎖的信息
七 使用注意事項
如何避免死鎖
1 使用事務(wù)時,盡量縮短事務(wù)的邏輯處理過程,及早提交或回滾事務(wù);
2 設(shè)置死鎖超時參數(shù)為合理范圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優(yōu)化程序,檢查并避免死鎖現(xiàn)象出現(xiàn);
4 .對所有的腳本和SP都要仔細(xì)測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL Server事務(wù)的默認(rèn)級別。不推薦強行加鎖
八 幾個有關(guān)鎖的問題
1 如何鎖一個表的某一行
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDSELECT * FROM table ROWLOCK WHERE id =
1
2 鎖定數(shù)據(jù)庫的一個表
SELECT * FROM table WITH (HOLDLOCK)
加鎖語句:
sybase:update 表 set col1=col1 where 1=0 ;MS SQL:select col1 from 表 (tablockx) where 1=0 ;oracle:LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖后其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖
幾個例子幫助大家加深印象,設(shè)table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
1)排它鎖
新建兩個連接,在第一個連接中執(zhí)行以下語句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'
--等待30秒commit tran
在第二個連接中執(zhí)行以下語句
begin transelect * from table1where B='b2'commit tran
若同時執(zhí)行上述兩個語句,則select查詢必須等待update執(zhí)行完畢才能執(zhí)行即要等待30秒
2)共享鎖
在第一個連接中執(zhí)行以下語句
begin transelect * from table1 holdlock -holdlock人為加鎖where B='b2'waitfor delay '00:00:30'
--等待30秒commit tran
在第二個連接中執(zhí)行以下語句
begin transelect A,C from table1where B='b2'update table1set A='aa'where B='b2'commit tran
若同時執(zhí)行上述兩個語句,則第二個連接中的select查詢可以執(zhí)行,而update必須等待第一個事務(wù)釋放共享鎖轉(zhuǎn)為排它鎖后才能執(zhí)行 即要等待30秒
3)死鎖
增設(shè)table2(D,E)
D E
d1 e1
d2 e2
在第一個連接中執(zhí)行以下語句
begin tranupdate table1set A='aa'where B='b2'waitfor delay '00:00:30'update table2set D='d5'where E='e1'commit tran
在第二個連接中執(zhí)行以下語句
begin tranupdate table2set D='d5'where E='e1'waitfor delay '00:00:10'update table1set A='aa'where B='b2'commit tran
同時執(zhí)行,系統(tǒng)會檢測出死鎖,并中止進程
補充一點:
SQL Server 2000支持的表級鎖定提示
HOLDLOCK 持有共享鎖,直到整個事務(wù)完成,應(yīng)該在被鎖對象不需要時立即釋放,等于SERIALIZABLE事務(wù)隔離級別
NOLOCK 語句執(zhí)行時不發(fā)出共享鎖,允許臟讀 ,等于 READ UNCOMMITTED事務(wù)隔離級別
PAGLOCK 在使用一個表鎖的地方用多個頁鎖
READPAST 讓SQL Server跳過任何鎖定行,執(zhí)行事務(wù),適用于READ UNCOMMITTED事務(wù)隔離級別只跳過RID鎖,不跳過頁,區(qū)域和表鎖
ROWLOCK 強制使用行鎖
TABLOCKX 強制使用獨占表級鎖,這個鎖在事務(wù)期間阻止任何其他事務(wù)使用這個表
UPLOCK 強制在讀表時使用更新而不用共享鎖
應(yīng)用程序鎖:
應(yīng)用程序鎖就是客戶端代碼生成的鎖,而不是SQL Server本身生成的鎖
處理應(yīng)用程序鎖的兩個過程
sp_getapplock 鎖定應(yīng)用程序資源
sp_releaseapplock 為應(yīng)用程序資源解鎖
注意: 鎖定數(shù)據(jù)庫的一個表的區(qū)別
SELECT * FROM table WITH (HOLDLOCK) 其他事務(wù)可以讀取表,但不能更新刪除
SELECT * FROM table WITH (TABLOCKX) 其他事務(wù)不能讀取表,更新和刪除
網(wǎng)站題目:sqlserver封鎖,sqlserver 死鎖解決方案
文章位置:http://chinadenli.net/article23/dsijecs.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、網(wǎng)站策劃、ChatGPT、移動網(wǎng)站建設(shè)、品牌網(wǎng)站制作、App開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)