数据库并发学习总结
數據庫并發控制
1. ?在數據庫中為什么要并發控制?
答:數據庫是共享資源,通常有許多個事務同時在運行。當多個事務并發地存取數據庫時就會產生同時讀取和/或修改同一數據的情況。若對并發操作不加控制就可能會存取和存儲不正確的數據,破壞數據庫的一致性。所以數據庫管理系統必須提供并發控制機制。
2 .并發操作可能會產生哪幾類數據不一致?用什么方法能避免各種不一致的情況?
答:并發操作帶來的數據不一致性包括三類:丟失修改、不可重復讀和讀“臟’夕數據。 ( l )丟失修改(lost update ) 兩個事務 Tl 和T2讀入同一數據并修改,T2提交的結果破壞了(覆蓋了) Tl 提交的結果,導致 Tl 的修改被丟失。 ( 2 )不可重復讀( Non 一 Repeatable Read ) 不可重復讀是指事務 Tl 讀取數據后,事務幾執行更新操作,使 Tl 無法再現前一次讀取結果。( 3 )讀“臟”數據( Dirty Read ) 讀“臟’夕數據是指事務 Tl 修改某一數據,并將其寫回磁盤,事務幾讀取同一數據后, Tl 由于某種原因被撤銷,這時 Tl 已修改過的數據恢復原值,幾讀到的數據就與數據庫中的數據不一致,則幾讀到的數據就為“臟”數據,即不正確的數據。避免不一致性的方法和技術就是并發控制。最常用的技術是封鎖技術。也可以用其他技術,例如在分布式數據庫系統中可以采用時間戳方法來進行并發控制。
3 .什么是封鎖?基本的封鎖類型有幾種?試述它們的含義。
答:封鎖就是事務 T 在對某個數據對象例如表、記錄等操作之前,先向系統發出請求,對其加鎖。加鎖后事務 T 就對該數據對象有了一定的控制,在事務 T 釋放它的鎖之前,其他的事務不能更新此數據對象。封鎖是實現并發控制的一個非常重要的技術。
基本的封鎖類型有兩種:排它鎖( Exclusive Locks ,簡稱 x 鎖)和共享鎖 ( Share Locks,簡稱 S 鎖)。排它鎖又稱為寫鎖。若事務 T 對數據對象 A 加上 X 鎖,則只允許 T 讀取和修改 A ,其他任何事務都不能再對 A 加任何類型的鎖,直到 T 釋放 A 上的鎖。這就保證了其他事務在 T 釋放 A 上的鎖之前不能再讀取和修改 A 。共享鎖又稱為讀鎖。若事務 T 對數據對象 A 加上 S 鎖,則事務 T 可以讀 A但不能修改 A ,其他事務只能再對 A 加 S 鎖,而不能加 X 鎖,直到 T 釋放 A 上的 S 鎖。這就保證了其他事務可以讀 A ,但在 T 釋放 A 上的 S 鎖之前不能對 A 做任何修改。
4 .如何用封鎖機制保證數據的一致性?
答: DBMS 在對數據進行讀、寫操作之前首先對該數據執行封鎖操作,例如下圖中事務 Tl 在對 A 進行修改之前先對 A 執行 xock ( A ) ,即對 A 加 x 鎖。這樣,當幾請求對 A 加 x 鎖時就被拒絕,幾只能等待 Tl 釋放 A 上的鎖后才能獲得對 A 的 x 鎖,這時它讀到的 A 是 Tl 更新后的值,再按此新的 A 值進行運算。這樣就不會丟失 Tl 的更新。
DBMS 按照一定的封鎖協議,對并發操作進行控制,使得多個并發操作有序地執行,就可以避免丟失修改、不可重復讀和讀“臟’夕數據等數據不一致性。
5 .什么是活鎖?什么是死鎖?
答:
如果事務 Tl 封鎖了數據 R ,事務幾又請求封鎖 R ,于是幾等待。幾也請求封鎖 R ,當 Tl 釋放了 R 上的封鎖之后系統首先批準了幾的請求,幾仍然等待。然后幾又請求封鎖 R ,當幾釋放了 R 上的封鎖之后系統又批準了幾的請求 … … 幾有可能永遠等待,這就是活鎖的情形。活鎖的含義是該等待事務等待時間太長,似乎被鎖住了,實際上可能被激活。如果事務 Tl 封鎖了數據 Rl ,幾封鎖了數據凡,然后 Tl 又請求封鎖幾,因幾已封鎖了幾,于是 Tl 等待幾釋放幾上的鎖。接著幾又申請封鎖 Rl ,因 Tl 已封鎖了 Rl ,幾也只能等待 Tl 釋放 Rl 上的鎖。這樣就出現了 Tl 在等待幾,而幾又在等待 T }的局面, T }和幾兩個事務永遠不能結束,形成死鎖。
6 .試述活鎖的產生原因和解決方法。
答:活鎖產生的原因:當一系列封鎖不能按照其先后順序執行時,就可能導致一些事務無限期等待某個封鎖,從而導致活鎖。避免活鎖的簡單方法是采用先來先服務的策略。當多個事務請求封鎖同一數據對象時,封鎖子系統按請求封鎖的先后次序對事務排隊,數據對象上的鎖一旦釋放就批準申請隊列中第一個事務獲得鎖。
11 .請給出檢測死鎖發生的一種方法,當發生死鎖后如何解除死鎖?
答:數據庫系統一般采用允許死鎖發生, DBMS 檢測到死鎖后加以解除的方法。 DBMS 中診斷死鎖的方法與操作系統類似,一般使用超時法或事務等待圖法。超時法是:如果一個事務的等待時間超過了規定的時限,就認為發生了死鎖。超時法實現簡單,但有可能誤判死鎖,事務因其他原因長時間等待超過時限時,系統會誤認為發生了死鎖。若時限設置得太長,又不能及時發現死鎖發生。 DBMS 并發控制子系統檢測到死鎖后,就要設法解除。通常采用的方法是選擇一個處理死鎖代價最小的事務,將其撤消,釋放此事務持有的所有鎖,使其他事務得以繼續運行下去。當然,對撤銷的事務所執行的數據修改操作必須加以恢復。
?12 .什么樣的并發調度是正確的調度?
答:可串行化( Serializable )的調度是正確的調度。可串行化的調度的定義:多個事務的并發執行是正確的,當且僅當其結果與按某一次序串行執行它們時的結果相同,稱這種調度策略為可串行化的調度。
9 .設 Tl ,幾,幾是如下的 3 個事務:
Tl :A : = A + 2 ;
T2:A : = A * 2 ;
T3:A : = A **2 ; ( A <-A*A)
設 A 的初值為 0 。
( l )若這 3 個事務允許并行執行,則有多少可能的正確結果,請一一列舉出來。
答 :A 的最終結果可能有 2 、 4 、 8 、 16 。因為串行執行次序有 Tl T2T3、 Tl T3T2、T2T1T3、T2T3Tl 、T3T1T2、T3T2 Tl 。對應的執行結果是 16 、 8 · 4 · 2 · 4 · 2 。
( 2 )請給出一個可串行化的調度,并給出執行結果
答:
最后結果 A 為 16 ,是可串行化的調度。
( 3 )請給出一個非串行化的調度,并給出執行結果。
答:最后結果 A 為 0 ,為非串行化的調度。
( 4 )若這 3 個事務都遵守兩段鎖協議,請給出一個不產生死鎖的可串行化調度。
答: ? ??
? ? ?( 5 )若這 3 個事務都遵守兩段鎖協議,請給出一個產生死鎖的調度。
答: ? ??
11.試證明,若并發事務遵守兩段鎖協議,則對這些事務的并發調度是可串行化的。
證明:首先以兩個并發事務 Tl 和T2為例,存在多個并發事務的情形可以類推。根據可串行化定義可知,事務不可串行化只可能發生在下列兩種情況:
?( l )事務 Tl 寫某個數據對象 A ,T2讀或寫 A ;
( 2 )事務 Tl 讀或寫某個數據對象 A ,T2寫 A 。
下面稱 A 為潛在沖突對象。
設 Tl 和T2訪問的潛在沖突的公共對象為{A1,A2 … , An }。不失一般性,假設這組潛在沖突對象中 X =(A 1 , A2 , … , Ai }均符合情況 1 。 Y ={A i + 1 , … , An }符合所情況( 2 )。
VX ∈ x , Tl 需要 XlockX ①
T2 需要 Slockx 或 Xlockx ②
?1 )如果操作 ① 先執行,則 Tl 獲得鎖,T2等待
由于遵守兩段鎖協議, Tl 在成功獲得 x 和 Y 中全部對象及非潛在沖突對象的鎖后,才會釋放鎖。
這時如果存在 w ∈ x 或 Y ,T2已獲得 w 的鎖,則出現死鎖;否則, Tl 在對 x 、 Y 中對象全部處理完畢后,T2才能執行。這相當于按 Tl 、T2的順序串行執行,根據可串行化定義, Tl 和幾的調度是可串行化的。
2 )操作 ② 先執行的情況與( l )對稱因此,若并發事務遵守兩段鎖協議,在不發生死鎖的情況下,對這些事務的并發調度一定是可串行化的。證畢。
12 .舉例說明,對并發事務的一個調度是可串行化的,而這些并發事務不一定遵守兩段鎖協議。
答:
13 .為什么要引進意向鎖?意向鎖的含義是什么?
答:引進意向鎖是為了提高封鎖子系統的效率。該封鎖子系統支持多種封鎖粒度。原因是:在多粒度封鎖方法中一個數據對象可能以兩種方式加鎖 ― 顯式封鎖和隱式封鎖。因此系統在對某一數據對象加鎖時不僅要檢查該數據對象上有無(顯式和隱式)封鎖與之沖突,還要檢查其所有上級結點和所有下級結點,看申請的封鎖是否與這些結點上的(顯式和隱式)封鎖沖突,顯然,這樣的檢查方法效率很低。為此引進了意向鎖。意向鎖的含義是:對任一結點加鎖時,必須先對它的上層結點加意向鎖。例如事務 T 要對某個元組加 X 鎖,則首先要對關系和數據庫加 ix 鎖。換言之,對關系和數據庫加 ix 鎖,表示它的后裔結點 ― 某個元組擬(意向)加 X 鎖。引進意向鎖后,系統對某一數據對象加鎖時不必逐個檢查與下一級結點的封鎖沖突了。例如,事務 T 要對關系 R 加 X 鎖時,系統只要檢查根結點數據庫和 R 本身是否已加了不相容的鎖(如發現已經加了 ix ,則與 X 沖突),而不再需要搜索和檢查 R 中的每一個元組是否加了 X 鎖或 S 鎖。
14 .試述常用的意向鎖: IS 鎖、 ix 鎖、 SIX 鎖,給出這些鎖的相容矩陣。
答: IS鎖:如果對一個數據對象加 IS 鎖,表示它的后裔結點擬(意向)加 S 鎖。例如,要對某個元組加 S 鎖,則要首先對關系和數據庫加 IS 鎖
IX 鎖:如果對一個數據對象加 ix 鎖,表示它的后裔結點擬(意向功口 X 鎖。例如,要對某個元組加 X 鎖,則要首先對關系和數據庫加 ix 鎖。
SIX 鎖:如果對一個數據對象加 SIX 鎖,表示對它加 S 鎖,再加 IX 鎖,即 SIX = S + IX 。
相容矩陣:
15 .理解并解釋下列術語的含義:封鎖、活鎖、死鎖、排它鎖、共享鎖、并發事務的調度、可串行化的調度、兩段鎖協議。
答:(略,已經在上面有關習題中解答)
16 .試述你了解的某一個實際的 DBMS 產品的并發控制機制。
答:(略,參見簡單介紹了有關 Oracle 的并發控制機制。
========
大數據量高并發的數據庫優化
一、數據庫結構的設計? ? 如果不能設計一個合理的數據庫模型,不僅會增加客戶端和服務器段程序的編程和維護的難度,而且將會影響系統實際運行的性能。所以,在一個系統開始實施之前,完備的數據庫模型的設計是必須的。
? ? 在一個系統分析、設計階段,因為數據量較小,負荷較低。我們往往只注意到功能的實現,而很難注意到性能的薄弱之處,等到系統投入實際運行一段時間后,才發現系統的性能在降低,這時再來考慮提高系統性能則要花費更多的人力物力,而整個系統也不可避免的形成了一個打補丁工程。
? ? 所以在考慮整個系統的流程的時候,我們必須要考慮,在高并發大數據量的訪問情況下,我們的系統會不會出現極端的情況。(例如:對外統計系統在7月16日出現的數據異常的情況,并發大數據量的的訪問造成,數據庫的響應時間不能跟上數據刷新的速度造成。具體情況是:在日期臨界時(00:00:00),判斷數據庫中是否有當前日期的記錄,沒有則插入一條當前日期的記錄。在低并發訪問的情況下,不會發生問題,但是當日期臨界時的訪問量相當大的時候,在做這一判斷的時候,會出現多次條件成立,則數據庫里會被插入多條當前日期的記錄,從而造成數據錯誤。),數據庫的模型確定下來之后,我們有必要做一個系統內數據流向圖,分析可能出現的瓶頸。
? ? 為了保證數據庫的一致性和完整性,在邏輯設計的時候往往會設計過多的表間關聯,盡可能的降低數據的冗余。(例如用戶表的地區,我們可以把地區另外存放到一個地區表中)如果數據冗余低,數據的完整性容易得到保證,提高了數據吞吐速度,保證了數據的完整性,清楚地表達數據元素之間的關系。而對于多表之間的關聯查詢(尤其是大數據表)時,其性能將會降低,同時也提高了客戶端程序的編程難度,因此,物理設計需折衷考慮,根據業務規則,確定對關聯表的數據量大小、數據項的訪問頻度,對此類數據表頻繁的關聯查詢應適當提高數據冗余設計但增加了表間連接查詢的操作,也使得程序的變得復雜,為了提高系統的響應時間,合理的數據冗余也是必要的。設計人員在設計階段應根據系統操作的類型、頻度加以均衡考慮。
? ?另外,最好不要用自增屬性字段作為主鍵與子表關聯。不便于系統的遷移和數據恢復。對外統計系統映射關系丟失(******************)。
? ? 原來的表格必須可以通過由它分離出去的表格重新構建。使用這個規定的好處是,你可以確保不會在分離的表格中引入多余的列,所有你創建的表格結構都與它們的實際需要一樣大。應用這條規定是一個好習慣,不過除非你要處理一個非常大型的數據,否則你將不需要用到它。(例如一個通行證系統,我可以將USERID,USERNAME,USERPASSWORD,單獨出來作個表,再把USERID作為其他表的外鍵)
表的設計具體注意的問題:
? ? 1、數據行的長度不要超過8020字節,如果超過這個長度的話在物理頁中這條數據會占用兩行從而造成存儲碎片,降低查詢效率。
? ? 2、能夠用數字類型的字段盡量選擇數字類型而不用字符串類型的(電話號碼),這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接回逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。
? ? 3、對于不可變字符類型char和可變字符類型varchar 都是8000字節,char查詢快,但是耗存儲空間,varchar查詢相對慢一些但是節省存儲空間。在設計字段的時候可以靈活選擇,例如用戶名、密碼等長度變化不大的字段可以選擇CHAR,對于評論等長度變化大的字段可以選擇VARCHAR。
? ? 4、字段的長度在最大限度的滿足可能的需要的前提下,應該盡可能的設得短一些,這樣可以提高查詢的效率,而且在建立索引的時候也可以減少資源的消耗。
二、查詢的優化?
保證在實現功能的基礎上,盡量減少對數據庫的訪問次數;通過搜索參數,盡量減少對表的訪問行數,最小化結果集,從而減輕網絡負擔;能夠分開的操作盡量分開處理,提高每次的響應速度;在數據窗口使用SQL時,盡量把使用的索引放在選擇的首列;算法的結構盡量簡單;在查詢時,不要過多地使用通配符如SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下盡量限制盡量結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因為某些情況下用戶是不需要那么多的數據的。 ??
在沒有建索引的情況下,數據庫查找某一條數據,就必須進行全表掃描了,對所有數據進行一次遍歷,查找出符合條件的記錄。在數據量比較小的情況下,也許看不出明顯的差別,但是當數據量大的情況下,這種情況就是極為糟糕的了。
SQL語句在SQL SERVER中是如何執行的,他們擔心自己所寫的SQL語句會被SQL SERVER誤解。比如:?
select * from table1 where name='zhangsan' and tID > 10000?
和執行:?
select * from table1 where tID > 10000 and name='zhangsan'?
一些人不知道以上兩條語句的執行效率是否一樣,因為如果簡單的從語句先后上看,這兩個語句的確是不一樣,如果tID是一個聚合索引,那么后一句僅僅從表的10000條以后的記錄中查找就行了;而前一句則要先從全表中查找看有幾個name='zhangsan'的,而后再根據限制條件條件tID>10000來提出查詢結果。?
事實上,這樣的擔心是不必要的。SQL SERVER中有一個“查詢分析優化器”,它可以計算出where子句中的搜索條件并確定哪個索引能縮小表掃描的搜索空間,也就是說,它能實現自動優化。雖然查詢優化器可以根據where子句自動的進行查詢優化,但有時查詢優化器就會不按照您的本意進行快速查詢。?
在查詢分析階段,查詢優化器查看查詢的每個階段并決定限制需要掃描的數據量是否有用。如果一個階段可以被用作一個掃描參數(SARG),那么就稱之為可優化的,并且可以利用索引快速獲得所需數據。?
SARG的定義:用于限制搜索的一個操作,因為它通常是指一個特定的匹配,一個值的范圍內的匹配或者兩個以上條件的AND連接。形式如下:?
列名 操作符 <常數 或 變量> 或 <常數 或 變量> 操作符 列名?
列名可以出現在操作符的一邊,而常數或變量出現在操作符的另一邊。如:?
Name=’張三’?
價格>5000?
5000<價格?
Name=’張三’ and 價格>5000?
如果一個表達式不能滿足SARG的形式,那它就無法限制搜索的范圍了,也就是SQL SERVER必須對每一行都判斷它是否滿足WHERE子句中的所有條件。所以一個索引對于不滿足SARG形式的表達式來說是無用的。?
? ? 所以,優化查詢最重要的就是,盡量使語句符合查詢優化器的規則避免全表掃描而使用索引查詢。
具體要注意的:
1.應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:
select id from t where num=0
2.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。優化器將無法通過索引來確定將要命中的行數,因此需要搜索該表的所有行。
3.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
4.in 和 not in 也要慎用,因為IN會使系統無法使用索引,而只能直接搜索表中的數據。如:
select id from t where num in(1,2,3)
對于連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
5.盡量避免在索引過的字符數據中,使用非打頭字母搜索。這也使得引擎無法利用索引。?
見如下例子:?
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’?
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’?
SELECT * FROM T1 WHERE NAME LIKE ‘L%’?
即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務。而第三個查詢能夠使用索引來加快操作。
6.必要時強制查詢優化器使用某個索引,如在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
7.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
SELECT * FROM T1 WHERE F1/2=100?
應改為:?
SELECT * FROM T1 WHERE F1=100*2
SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’?
應改為:?
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
SELECT member_number, first_name, last_name FROM members?
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21?
應改為:?
SELECT member_number, first_name, last_name FROM members?
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())?
即:任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。
8.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
9.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
10.在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,并且應盡可能的讓字段順序與索引順序相一致。
11.很多時候用 exists是一個好的選擇:
elect num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
SELECT SUM(T1.C1)FROM T1 WHERE(?
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)?
SELECT SUM(T1.C1) FROM T1WHERE EXISTS(?
SELECT * FROM T2 WHERE T2.C2=T1.C2)?
兩者產生相同的結果,但是后者的效率顯然要高于前者。因為后者不會產生大量鎖定的表掃描或是索引掃描。
如果你想校驗表里是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費服務器資源。可以用EXISTS代替。如:?
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')?
可以寫成:?
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
經常需要寫一個T_SQL語句比較一個父結果集和子結果集,從而找到是否存在在父結果集中有而在子結果集中沒有的記錄,如:?
SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用別名a代替?
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)?
SELECT a.hdr_key FROM hdr_tbl a?
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL?
SELECT hdr_key FROM hdr_tbl?
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)?
三種寫法都可以得到同樣正確的結果,但是效率依次降低。
12.盡量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。
13.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
14.臨時表并不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對于一次性事件,最好使用導出表。
15.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。
16.如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。?
17.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句后向客戶端發送 DONE_IN_PROC 消息。
18.盡量避免大事務操作,提高系統并發能力。
19.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。?
20. 避免使用不兼容的數據類型。例如float和int、char和varchar、binary和varbinary是不兼容的。數據類型的不兼容可能使優化器無法執行一些本來可以進行的優化操作。例如:?
SELECT name FROM employee WHERE salary > 60000?
在這條語句中,如salary字段是money型的,則優化器很難對其進行優化,因為60000是個整型數。我們應當在編程時將整型轉化成為錢幣型,而不要等到運行時轉化。
21.充分利用連接條件,在某種情況下,兩個表之間可能不只一個的連接條件,這時在 WHERE 子句中將連接條件完整的寫上,有可能大大提高查詢速度。?
例:?
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO?
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO?
第二句將比第一句執行快得多。
22、使用視圖加速查詢?
把表的一個子集進行排序并創建視圖,有時能加速查詢。它有助于避免多重排序 操作,而且在其他方面還能簡化優化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns?
FROM cust,rcvbles?
WHERE cust.customer_id = rcvlbes.customer_id?
AND rcvblls.balance>0?
AND cust.postcode>“98000”?
ORDER BY cust.name
如果這個查詢要被執行多次而不止一次,可以把所有未付款的客戶找出來放在一個視圖中,并按客戶的名字進行排序:?
CREATE VIEW DBO.V_CUST_RCVLBES?
AS?
SELECT cust.name,rcvbles.balance,……other columns?
FROM cust,rcvbles?
WHERE cust.customer_id = rcvlbes.customer_id?
AND rcvblls.balance>0?
ORDER BY cust.name?
然后以下面的方式在視圖中查詢:?
SELECT * FROM V_CUST_RCVLBES?
WHERE postcode>“98000”?
視圖中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁盤I/O,所以查詢工作量可以得到大幅減少。
23、能用DISTINCT的就不用GROUP BY?
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID?
可改為:?
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
24.能用UNION ALL就不要用UNION?
UNION ALL不執行SELECT DISTINCT函數,這樣就會減少很多不必要的資源?
35.盡量不要用SELECT INTO語句。?
SELECT INOT 語句會導致表鎖定,阻止其他用戶訪問該表。
? ? 上面我們提到的是一些基本的提高查詢速度的注意事項,但是在更多的情況下,往往需要反復試驗比較不同的語句以得到最佳方案。最好的方法當然是測試,看實現相同功能的SQL語句哪個執行時間最少,但是數據庫中如果數據量很少,是比較不出來的,這時可以用查看執行計劃,即:把實現相同功能的多條SQL語句考到查詢分析器,按CTRL+L看查所利用的索引,表掃描次數(這兩個對性能影響最大),總體上看詢成本百分比即可。?
三、算法的優化
盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。.使用基于游標的方法或臨時表方法之前,應先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。與臨時表一樣,游標并不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用游標執行的速度快。如果開發時間允許,基于游標的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
游標提供了對特定集合中逐行掃描的手段,一般使用游標逐行遍歷數據,根據取出的數據不同條件進行不同的操作。尤其對多表和大表定義的游標(大的數據集合)循環很容易使程序進入一個漫長的等特甚至死機。?
在有些場合,有時也非得使用游標,此時也可考慮將符合條件的數據行轉入臨時表中,再對臨時表定義游標進行操作,可時性能得到明顯提高。
(例如:對內統計第一版)
封裝存儲過程
四、建立高效的索引
創建索引一般有以下兩個目的:維護被索引列的唯一性和提供快速訪問表中數據的策略。大型數據庫有兩種索引即簇索引和非簇索引,一個沒有簇索引的表是按堆結構存儲數據,所有的數據均添加在表的尾部,而建立了簇索引的表,其數據在物理上會按照簇索引鍵的順序存儲,一個表只允許有一個簇索引,因此,根據B樹結構,可以理解添加任何一種索引均能提高按索引列查詢的速度,但會降低插入、更新、刪除操作的性能,尤其是當填充因子(Fill Factor)較大時。所以對索引較多的表進行頻繁的插入、更新、刪除操作,建表和索引時因設置較小的填充因子,以便在各數據頁中留下較多的自由空間,減少頁分割及重新組織的工作。?
索引是從數據庫中獲取數據的最高效方式之一。95% 的數據庫性能問題都可以采用索引技術得到解決。作為一條規則,我通常對邏輯主鍵使用唯一的成組索引,對系統鍵(作為存儲過程)采用唯一的非成組索引,對任何外鍵列[字段]采用非成組索引。不過,索引就象是鹽,太多了菜就咸了。你得考慮數據庫的空間有多大,表如何進行訪問,還有這些訪問是否主要用作讀寫。?
實際上,您可以把索引理解為一種特殊的目錄。微軟的SQL SERVER提供了兩種索引:聚集索引(clustered index,也稱聚類索引、簇集索引)和非聚集索引(nonclustered index,也稱非聚類索引、非簇集索引)。下面,我們舉例來說明一下聚集索引和非聚集索引的區別:?
其實,我們的漢語字典的正文本身就是一個聚集索引。比如,我們要查“安”字,就會很自然地翻開字典的前幾頁,因為“安”的拼音是“an”,而按照拼音排序漢字的字典是以英文字母“a”開頭并以“z”結尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”開頭的部分仍然找不到這個字,那么就說明您的字典中沒有這個字;同樣的,如果查“張”字,那您也會將您的字典翻到最后部分,因為“張”的拼音是“zhang”。也就是說,字典的正文部分本身就是一個目錄,您不需要再去查其他目錄來找到您需要找的內容。?
我們把這種正文內容本身就是一種按照一定規則排列的目錄稱為“聚集索引”。?
如果您認識某個字,您可以快速地從自動中查到這個字。但您也可能會遇到您不認識的字,不知道它的發音,這時候,您就不能按照剛才的方法找到您要查的字,而需要去根據“偏旁部首”查到您要找的字,然后根據這個字后的頁碼直接翻到某頁來找到您要找的字。但您結合“部首目錄”和“檢字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“張”字,我們可以看到在查部首之后的檢字表中“張”的頁碼是672頁,檢字表中“張”的上面是“馳”字,但頁碼卻是63頁,“張”的下面是“弩”字,頁面是390頁。很顯然,這些字并不是真正的分別位于“張”字的上下方,現在您看到的連續的“馳、張、弩”三字實際上就是他們在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我們可以通過這種方式來找到您所需要的字,但它需要兩個過程,先找到目錄中的結果,然后再翻到您所需要的頁碼。?
我們把這種目錄純粹是目錄,正文純粹是正文的排序方式稱為“非聚集索引”。?
進一步引申一下,我們可以很容易的理解:每個表只能有一個聚集索引,因為目錄只能按照一種方法進行排序。
(一)何時使用聚集索引或非聚集索引?
下面的表總結了何時使用聚集索引或非聚集索引(很重要)。?
動作描述 使用聚集索引 使用非聚集索引?
列經常被分組排序 應 應?
返回某范圍內的數據 應 不應?
一個或極少不同值 不應 不應?
小數目的不同值 應 不應?
大數目的不同值 不應 應?
頻繁更新的列 不應 應?
外鍵列 應 應?
主鍵列 應 應?
頻繁修改索引列 不應 應
事實上,我們可以通過前面聚集索引和非聚集索引的定義的例子來理解上表。如:返回某范圍內的數據一項。比如您的某個表有一個時間列,恰好您把聚合索引建立在了該列,這時您查詢2004年1月1日至2004年10月1日之間的全部數據時,這個速度就將是很快的,因為您的這本字典正文是按日期進行排序的,聚類索引只需要找到要檢索的所有數據中的開頭和結尾數據即可;而不像非聚集索引,必須先查到目錄中查到每一項數據對應的頁碼,然后再根據頁碼查到具體內容。
(二)結合實際,談索引使用的誤區
理論的目的是應用。雖然我們剛才列出了何時應使用聚集索引或非聚集索引,但在實踐中以上規則卻很容易被忽視或不能根據實際情況進行綜合分析。下面我們將根據在實踐中遇到的實際問題來談一下索引使用的誤區,以便于大家掌握索引建立的方法。?
1、主鍵就是聚集索引?
這種想法筆者認為是極端錯誤的,是對聚集索引的一種浪費。雖然SQL SERVER默認是在主鍵上建立聚集索引的。?
通常,我們會在每個表中都建立一個ID列,以區分每條數據,并且這個ID列是自動增大的,步長一般為1。我們的這個辦公自動化的實例中的列Gid就是如此。此時,如果我們將這個列設為主鍵,SQL SERVER會將此列默認為聚集索引。這樣做有好處,就是可以讓您的數據在數據庫中按照ID進行物理排序,但筆者認為這樣做意義不大。?
顯而易見,聚集索引的優勢是很明顯的,而每個表中只能有一個聚集索引的規則,這使得聚集索引變得更加珍貴。?
從我們前面談到的聚集索引的定義我們可以看出,使用聚集索引的最大好處就是能夠根據查詢要求,迅速縮小查詢范圍,避免全表掃描。在實際應用中,因為ID號是自動生成的,我們并不知道每條記錄的ID號,所以我們很難在實踐中用ID號來進行查詢。這就使讓ID號這個主鍵作為聚集索引成為一種資源浪費。其次,讓每個ID號都不同的字段作為聚集索引也不符合“大數目的不同值情況下不應建立聚合索引”規則;當然,這種情況只是針對用戶經常修改記錄內容,特別是索引項的時候會負作用,但對于查詢速度并沒有影響。?
在辦公自動化系統中,無論是系統首頁顯示的需要用戶簽收的文件、會議還是用戶進行文件查詢等任何情況下進行數據查詢都離不開字段的是“日期”還有用戶本身的“用戶名”。?
通常,辦公自動化的首頁會顯示每個用戶尚未簽收的文件或會議。雖然我們的where語句可以僅僅限制當前用戶尚未簽收的情況,但如果您的系統已建立了很長時間,并且數據量很大,那么,每次每個用戶打開首頁的時候都進行一次全表掃描,這樣做意義是不大的,絕大多數的用戶1個月前的文件都已經瀏覽過了,這樣做只能徒增數據庫的開銷而已。事實上,我們完全可以讓用戶打開系統首頁時,數據庫僅僅查詢這個用戶近3個月來未閱覽的文件,通過“日期”這個字段來限制表掃描,提高查詢速度。如果您的辦公自動化系統已經建立的2年,那么您的首頁顯示速度理論上將是原來速度8倍,甚至更快。
2、只要建立索引就能顯著提高查詢速度?
事實上,我們可以發現上面的例子中,第2、3條語句完全相同,且建立索引的字段也相同;不同的僅是前者在fariqi字段上建立的是非聚合索引,后者在此字段上建立的是聚合索引,但查詢速度卻有著天壤之別。所以,并非是在任何字段上簡單地建立索引就能提高查詢速度。
從建表的語句中,我們可以看到這個有著1000萬數據的表中fariqi字段有5003個不同記錄。在此字段上建立聚合索引是再合適不過了。在現實中,我們每天都會發幾個文件,這幾個文件的發文日期就相同,這完全符合建立聚集索引要求的:“既不能絕大多數都相同,又不能只有極少數相同”的規則。由此看來,我們建立“適當”的聚合索引對于我們提高查詢速度是非常重要的。
3、把所有需要提高查詢速度的字段都加進聚集索引,以提高查詢速度?
上面已經談到:在進行數據查詢時都離不開字段的是“日期”還有用戶本身的“用戶名”。既然這兩個字段都是如此的重要,我們可以把他們合并起來,建立一個復合索引(compound index)。?
很多人認為只要把任何字段加進聚集索引,就能提高查詢速度,也有人感到迷惑:如果把復合的聚集索引字段分開查詢,那么查詢速度會減慢嗎?帶著這個問題,我們來看一下以下的查詢速度(結果集都是25萬條數據):(日期列fariqi首先排在復合聚集索引的起始列,用戶名neibuyonghu排在后列)?
我們可以看到如果僅用聚集索引的起始列作為查詢條件和同時用到復合聚集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的復合索引列還要略快(在查詢結果集數目一樣的情況下);而如果僅用復合聚集索引的非起始列作為查詢條件的話,這個索引是不起任何作用的。當然,語句1、2的查詢速度一樣是因為查詢的條目數一樣,如果復合索引的所有列都用上,而且查詢結果少的話,這樣就會形成“索引覆蓋”,因而性能可以達到最優。同時,請記住:無論您是否經常使用聚合索引的其他列,但其前導列一定要是使用最頻繁的列。
(三)其他注意事項?
“水可載舟,亦可覆舟”,索引也一樣。索引有助于提高檢索性能,但過多或不當的索引也會導致系統低效。因為用戶在表中每加進一個索引,數據庫就要做更多的工作。過多的索引甚至會導致索引碎片。?
所以說,我們要建立一個“適當”的索引體系,特別是對聚合索引的創建,更應精益求精,以使您的數據庫能得到高性能的發揮
?
好像沒有提到高并發的解決方案
索引的使用,學習了
?
高并發都用NoSQL了,內存數據庫是解決高并發實時性能的方向,
這里有國人開源的高并發框架 www. 8088net .com
========
怎么解決數據庫并發的問題
1.用一個標識,在選擇那張票的時候先用
(Update ?表 ?set ?票flag=‘占用了!’ ?where ?票flag=‘未占用’ ?and ?........)
這樣是保險的,不可能存在并發問題,這就牽扯到sql鎖機制問題了,你可以測試一下,其實sql中update是先查詢出然后刪除再添加,但由于使用了update,過程中就自動加鎖了,很方便吧
2.加鎖。
Microsoft® ?SQL ?Server™ ?2000 ?使用鎖定確保事務完整性和數據庫一致性。鎖定可以防止用戶讀取正在由其他用戶更改的數據,并可以防止多個用戶同時更改相同數據。如果不使用鎖定,則數據庫中的數據可能在邏輯上不正確,并且對數據的查詢可能會產生意想不到的結果。
雖然 ?SQL ?Server ?自動強制鎖定,但可以通過了解鎖定并在應用程序中自定義鎖定來設計更有效的應用程序。
========
關于數據庫的并發性的一個解決方案
我先把流程說出來,,比如修改一個記錄:
當用戶點修改時,從數據庫讀出數據并顯示到編輯菜單中,然后再編輯數據,再點確定保存到數據庫中。如果多個用戶,當A用戶點修改到保存該數據這一時間段,,B用戶不能修改,,這個好像不能用事務來做吧,,,大家給個解決方案,,但是我覺得還有點矛盾。當這一時間段用戶能修改,那么對于A用戶來說數據就已經不一致了,A用戶看到的是B用戶沒有修改前的數據,如果不能修改,也不現實,,如果B用戶點了修改還沒點確定,,然后用戶出去辦急事或WC,,那A用戶不是一直等,,,
網上經常舉賣車票的例子,當售票員A聽到買票人后開始查詢,發現有2張,,買票人正好要2張,,在查詢和售出這一時間段,如果其它窗口不能賣,,好像不太現實,,有時這一時間段還是很長的,,一分鐘左右吧,,其它10多個窗口窗口不能賣這一車次的不是很要命,并且每個窗口都會差不多占一車次的查詢,,如果在查詢到確定出售這一價段其它窗口可以賣,,也出現問題了,,售票員A查詢發現剩兩張,,告訴買票的人,正好剩兩張,,這時客戶確定要,如果在這一時間段,其它窗口賣一張,,那在確定賣出去時將會失敗,難道要跟買票人解釋。,,這問題其它也困我很久了,,謝謝大家給我一個解決方案,,也許是我想錯了,,在線等
SQL的鎖機制
一. 為什么要引入鎖
多個用戶同時對數據庫的并發操作時會帶來以下數據不一致的問題:
丟失更新
A,B兩個用戶讀同一數據并進行修改,其中一個用戶的修改結果破壞了另一個修改的結果,比如訂票系統
臟讀
A用戶修改了數據,隨后B用戶又讀出該數據,但A用戶因為某些原因取消了對數據的修改,數據恢復原值,此時B得到的數據就與數據庫內的數據產生了不一致
不可重復讀
A用戶讀取數據,隨后B用戶讀出該數據并修改,此時A用戶再讀取數據時發現前后兩次的值不一致
并發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶做某些操作以避免產生數據不一致
二 ?鎖的分類
鎖的類別有兩種分法:
1. ?從數據庫系統的角度來看:分為獨占鎖(即排它鎖),共享鎖和更新鎖
MS-SQL Server 使用以下資源鎖模式。
鎖模式 ? ? ?描述?
共享 ? ? ? ?(S) 用于不更改或不更新數據的操作(只讀操作),如 SELECT 語句。?
更新 (U) ? ? 用于可更新的資源中。防止當多個會話在讀取、鎖定以及隨后可能進行的資源更新時發生常見形式的死鎖。?
排它 (X) ? ? 用于數據修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進行多重更新。?
意向鎖 ? ? ? 用于建立鎖的層次結構。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。?
架構鎖 ? ? ? ?在執行依賴于表架構的操作時使用。架構鎖的類型為:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。?
大容量更新 (BU) 向表中大容量復制數據并指定了 TABLOCK 提示時使用。?
共享鎖
共享 (S) 鎖允許并發事務讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便立即釋放資源上的共享 (S) 鎖,除非將事務隔離級別設置為可重復讀或更高級別,或者在事務生存周期內用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然后修改行,此操作要求鎖轉換為排它 (X) 鎖。如果兩個事務獲得了資源上的共享模式鎖,然后試圖同時更新數據,則一個事務嘗試將鎖轉換為排它 (X) 鎖。共享模式到排它鎖的轉換必須等待一段時間,因為一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它 (X) 鎖以進行更新。由于兩個事務都要轉換為排它 (X) 鎖,并且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。
若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。
排它鎖
排它 (X) 鎖可以防止并發事務對資源進行訪問。其它事務不能讀取或修改排它 (X) 鎖鎖定的數據。
意向鎖
意向鎖表示 SQL Server 需要在層次結構中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享 (S) 鎖。在表級設置意向鎖可防止另一個事務隨后在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。
意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
鎖模式 描述?
意向共享 (IS) 通過在各資源上放置 S 鎖,表明事務的意向是讀取層次結構中的部分(而不是全部)底層資源。?
意向排它 (IX) 通過在各資源上放置 X 鎖,表明事務的意向是修改層次結構中的部分(而不是全部)底層資源。IX 是 IS 的超集。?
與意向排它共享 (SIX) 通過在各資源上放置 IX 鎖,表明事務的意向是讀取層次結構中的全部底層資源并修改部分(而不是全部)底層資源。允許頂層資源上的并發 IS 鎖。例如,表的 SIX 鎖在表上放置一個 SIX 鎖(允許并發 IS 鎖),在當前所修改頁上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個資源在一段時間內只能有一個 SIX 鎖,以防止其它事務對資源進行更新,但是其它事務可以通過獲取表級的 IS 鎖來讀取層次結構中的底層資源。?
獨占鎖:只允許進行鎖定操作的程序使用,其他任何對他的操作均不會被接受。執行數據更新命令時,SQL Server會自動使用獨占鎖。當對象上有其他鎖存在時,無法對其加獨占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無法修改它,在執行Select時,SQL Server會對對象加共享鎖。
更新鎖:當SQL Server準備更新數據時,它首先對數據對象作更新鎖鎖定,這樣數據將不能被修改,但可以讀取。等到SQL Server確定要進行更新數據操作時,他會自動將更新鎖換為獨占鎖,當對象上有其他鎖存在時,無法對其加更新鎖。
2. 從程序員的角度看:分為樂觀鎖和悲觀鎖。
樂觀鎖:完全依靠數據庫來管理鎖的工作。
悲觀鎖:程序員自己管理數據或對象上的鎖處理。
MS-SQLSERVER 使用鎖在多個同時在數據庫內執行修改的用戶間實現悲觀并發控制
三 ?鎖的粒度
? ?鎖粒度是被封鎖目標的大小,封鎖粒度小則并發性高,但開銷大,封鎖粒度大則并發性低但開銷小
SQL Server支持的鎖粒度可以分為為行、頁、鍵、鍵范圍、索引、表或數據庫獲取鎖
資源 ? ? ? ? 描述?
RID ? ? ? ? 行標識符。用于單獨鎖定表中的一行。?
鍵 ? ? ? ? ? 索引中的行鎖。用于保護可串行事務中的鍵范圍。?
頁 ? ? ? ? ? 8 千字節 (KB) 的數據頁或索引頁。?
擴展盤區 ? ? 相鄰的八個數據頁或索引頁構成的一組。?
表 ? ? ? ? ? 包括所有數據和索引在內的整個表。?
DB ? ? ? ? ?數據庫。?
四 ?鎖定時間的長短
鎖保持的時間長度為保護所請求級別上的資源所需的時間長度。?
用于保護讀取操作的共享鎖的保持時間取決于事務隔離級別。采用 READ COMMITTED 的默認事務隔離級別時,只在讀取頁的期間內控制共享鎖。在掃描中,直到在掃描內的下一頁上獲取鎖時才釋放鎖。如果指定 HOLDLOCK 提示或者將事務隔離級別設置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務結束才釋放鎖。
根據為游標設置的并發選項,游標可以獲取共享模式的滾動鎖以保護提取。當需要滾動鎖時,直到下一次提取或關閉游標(以先發生者為準)時才釋放滾動鎖。但是,如果指定 HOLDLOCK,則直到事務結束才釋放滾動鎖。
用于保護更新的排它鎖將直到事務結束才釋放。?
如果一個連接試圖獲取一個鎖,而該鎖與另一個連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:?
將沖突鎖釋放而且連接獲取了所請求的鎖。
連接的超時間隔已到期。默認情況下沒有超時間隔,但是一些應用程序設置超時間隔以防止無限期等待?
五 ?SQL Server 中鎖的自定義?
1 處理死鎖和設置死鎖優先級
死鎖就是多個用戶申請不同封鎖,由于申請者均擁有一部分封鎖權而又等待其他用戶擁有的部分封鎖而引起的無休止的等待
可以使用SET DEADLOCK_PRIORITY控制在發生死鎖情況時會話的反應方式。如果兩個進程都鎖定數據,并且直到其它進程釋放自己的鎖時,每個進程才能釋放自己的鎖,即發生死鎖情況。
2 ?處理超時和設置鎖超時持續時間。
@@LOCK_TIMEOUT 返回當前會話的當前鎖超時設置,單位為毫秒
SET LOCK_TIMEOUT 設置允許應用程序設置語句等待阻塞資源的最長時間。當語句等待的時間大于 LOCK_TIMEOUT 設置時,系統將自動取消阻塞的語句,并給應用程序返回"已超過了鎖請求超時時段"的 1222 號錯誤信息
示例?
下例將鎖超時期限設置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800
3) ?設置事務隔離級別。
參見 http://expert.csdn.net/Expert/topic/1785/1785314.xml?temp=.3050501
4 ) ?對 SELECT、INSERT、UPDATE 和 DELETE 語句使用表級鎖定提示。
5) ? 配置索引的鎖定粒度
可以使用 sp_indexoption 系統存儲過程來設置用于索引的鎖定粒度
六 ?查看鎖的信息
1 ? 執行 EXEC SP_LOCK 報告有關鎖的信息
2 ? 查詢分析器中按Ctrl+2可以看到鎖的信息
七 ?使用注意事項
如何避免死鎖
1 使用事務時,盡量縮短事務的邏輯處理過程,及早提交或回滾事務;
2 設置死鎖超時參數為合理范圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 優化程序,檢查并避免死鎖現象出現;
4 .對所有的腳本和SP都要仔細測試,在正是版本之前。
5 所有的SP都要有錯誤處理(通過@error)
6 一般不要修改SQL SERVER事務的默認級別。不推薦強行加鎖
解決問題 如何對行 表 數據庫加鎖
八 ?幾個有關鎖的問題
1 如何鎖一個表的某一行
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED?
SELECT * FROM table ?ROWLOCK ?WHERE id = 1
2 鎖定數據庫的一個表
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解鎖
幾個例子幫助大家加深印象
設table1(A,B,C)
A ? ?B ? ?C
a1 ? b1 ? c1
a2 ? b2 ? c2
a3 ? b3 ? c3
1)排它鎖
新建兩個連接
在第一個連接中執行以下語句
begin tran
? update table1
? set A='aa'
? where B='b2'
? waitfor delay '00:00:30' ?--等待30秒
commit tran
在第二個連接中執行以下語句
begin tran
? select * from table1
? where B='b2' ??
commit tran
若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒
2)共享鎖
在第一個連接中執行以下語句
begin tran
? select * from table1 holdlock -holdlock人為加鎖
? where B='b2'?
? waitfor delay '00:00:30' ?--等待30秒
commit tran
在第二個連接中執行以下語句
begin tran
? select A,C from table1
? where B='b2'?
? update table1
? set A='aa'
? where B='b2' ??
commit tran
若同時執行上述兩個語句,則第二個連接中的select查詢可以執行
而update必須等待第一個事務釋放共享鎖轉為排它鎖后才能執行 即要等待30秒
3)死鎖
增設table2(D,E)
D ? ?E
d1 ? e1
d2 ? e2
在第一個連接中執行以下語句
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
??
在第二個連接中執行以下語句
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
同時執行,系統會檢測出死鎖,并中止進程
老大,你這我也懂,,但你這是技術,,我問的是解決方案,,車票系統到底用的哪種方案
SQL code
樓主參考下這個...悲觀鎖
?
悲觀鎖定解決方案
我們只要對上邊的代碼做微小的改變就可以實現悲觀的鎖定.
?
declare @CardNo varchar(20)
Begin Tran
?
? ? ? ?-- ?選擇一張未使用的卡
? ? ? ? select top 1 @CardNo=F_CardNo
? ? ? ? from Card ? with (UPDLOCK) ?where F_Flag=0
? ? ? ? ?
? ? ? ? -- ?延遲50秒,模擬并發訪問.
? ? ? ? waitfor delay '000:00:50'
?
? ? ? ?-- ?把剛才選擇出來的卡進行注冊.
?
? ? ? ? update Card
? ? ? ? set F_Name=user,
? ? ? ? ? ? F_Time=getdate(),
? ? ? ? ? ? F_Flag=1
? ? ? ? where F_CardNo=@CardNo
?
commit
?
注意其中的區別了嗎?with(updlock),是的,我們在查詢的時候使用了with (UPDLOCK)選項,在查詢記錄的時候我們就對記錄加上了更新鎖,表示我們即將對次記錄進行更新.注意更新鎖和共享鎖是不沖突的,也就是其他用戶還可以查詢此表的內容,但是和更新鎖和排它鎖是沖突的.所以其他的更新用戶就會阻塞.如果我們在另外一個窗口執行此代碼,同樣不加waifor delay子句.兩邊執行完畢后,我們發現成功的注冊了兩張卡.可能我們已經發現了悲觀鎖定的缺點:當一個用戶進行更新的事務的時候,其他更新用戶必須排隊等待,即使那個用戶更新的不是同一條記錄.
到底什么時候開始其它用戶不能操作,A用戶點擊修改時還是用戶點確定重新去讀一次數據庫時,
SQL code
--這里還有一個~ 之前保存的 - -出處在哪沒有記錄...很不好意思 作者請罵我吧...
?
樂觀鎖定解決方案
-- ?首先我們在Card表里邊加上一列F_TimeStamp 列,該列是varbinary(8)類型.但是在更新的時候這個值會自動增長.
?
alter table Card add ?F_TimeStamp timestamp not null
??
-- ?悲觀鎖定
declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int
?
Begin Tran
?
? ? ? ?-- ?取得卡號和原始的時間戳值
? ? ? ? select top 1 @CardNo=F_CardNo,
? ? ? ? ? ? ? ? ? ? ?@timestamp=F_TimeStamp
? ? ? ? from Card
? ? ? ? where F_Flag=0
? ? ? ? ?
? ? ? ? -- ?延遲50秒,模擬并發訪問.
? ? ? ? waitfor delay '000:00:50'
?
? ? ? ? -- ?注冊卡,但是要比較時間戳是否發生了變化.如果沒有發生變化.更新成功.如果發生變化,更新失敗.
?
? ? ? ? update Card
? ? ? ? set F_Name=user,
? ? ? ? ? ? F_Time=getdate(),
? ? ? ? ? ? F_Flag=1
? ? ? ? where F_CardNo=@CardNo and F_TimeStamp=@timestamp
? ? ? ? set @rowcount=@@rowcount
? ? ? ? if @rowcount=1
? ? ? ? begin
? ? ? ? ? ? ? ? print '更新成功!'
? ? ? ? ? ? ? ? commit
? ? ? ? end
? ? ? ? else if @rowcount=0
? ? ? ? begin
? ? ? ? ? ? ? ? if exists(select 1 from Card where F_CardNo=@CardNo)
? ? ? ? ? ? ? ? begin
? ? ? ? ? ? ? ? ? ? ? ? print '此卡已經被另外一個用戶注冊!'
? ? ? ? ? ? ? ? ? ? ? ? rollback tran
? ? ? ? ? ? ? ? end
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? begin
? ? ? ? ? ? ? ? ? ? ? ? print '并不存在此卡!'
? ? ? ? ? ? ? ? ? ? ? ? rollback tran
? ? ? ? ? ? ? ? end
? ? ? ? end
?
在另外一個窗口里邊執行沒有waitfor的代碼,注冊成功后,返回原來的窗口,我們就會發現到時間后它顯示的提示是此卡以被另外一個用戶注冊的提示.很明顯,這樣我們也可以避免兩個用戶同時注冊一張卡的現象的出現.同時,使用這種方法的另外一個好處是沒有使用更新鎖,這樣增加的系統的并發處理能力.
加個rowversion字段,每當數據被修改時,此字段會被UPDATE,
保存時,判斷記錄是否已經被修改。
看來LZ沒有做過實際案例啊,現在我給你透露下實際售票系統中的一個方案例子:
? ?首先沒有那么復雜的鎖,實際應用會盡量從業務角度考慮避免沖突:
? ?實際售票系統是這樣:?
?
? ? ? ? ? ?1.售票中,"座位號" 才是競爭資源;
? ? ? ? ? ?2.售票中,查看票是不發生鎖號的.
? ? ? ? ? ?3.售票中,有個選票(選座位號)的動作,選座位號確定時,才發生鎖號(即鎖住改作為號,即使這鎖號,也只是修改標記,表示自己暫時鎖住);
? ? ? ? ? ?4.等客戶交錢后,就確定提交交易完成,這時候,就成為售出該票了(當然,被鎖的號,要修改為對應的已售標記,及其他流程操作).
從這個過程看,幾乎沒有那么多沖突出現(只有選號時,有可能已被別人選了,這也應該知道的,可以另選號),這就是方案.
樂觀鎖定解決方案
-- ?首先我們在Card表里邊加上一列F_TimeStamp 列,該列是varbinary(8)類型.但是在更新的時候這個值會自動增長.
alter table Card add ?F_TimeStamp timestamp not null
-- ?悲觀鎖定
declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int
Begin Tran
? ? ? ?--…
你這是當點確定后再去判斷是否卡否已被注冊了嘛,,我想知道車票出售系統或大型網絡版的管理系統的解決方案
利用小粒度鎖可以盡量避免沖突,分析好你的業務,沒多少問題。如7樓所言,一般的情況下,鎖使用并
看來LZ沒有做過實際案例啊,現在我給你透露下實際售票系統中的一個方案例子:
首先沒有那么復雜的鎖,實際應用會盡量從業務角度考慮避免沖突:
實際售票系統是這樣:
1.售票中,"座位號" 才是競爭資源;
2.售票中,查看票是不發生鎖號的.
3.售票中,有個選票(選座位號)的動作,選座位號確定時,才發生鎖號(即鎖住改作為號,即使這鎖號,也只是修改標記,表示自己暫時鎖住);
4.等客戶交錢后,就確定提交交易完成,這時候,就成為售出該…
同意,就是這個意思
看來LZ沒有做過實際案例啊,現在我給你透露下實際售票系統中的一個方案例子:?
? 首先沒有那么復雜的鎖,實際應用會盡量從業務角度考慮避免沖突:?
? 實際售票系統是這樣:?
? ? ? ? ? 1.售票中,"座位號" 才是競爭資源;?
? ? ? ? ? 2.售票中,查看票是不發生鎖號的.?
? ? ? ? ? 3.售票中,有個選票(選座位號)的動作,選座位號確定時,才發生鎖號(即鎖住改作為號,即使這鎖號,也只是修改標記,表示自己暫時鎖住);?
? ? ? ? ? 4.等…
謝謝,,,,,是不是在查看時去修改數據庫的記錄的一個標記,,當查看完了(取消或者售完票后)再將這個標記修改回去,,,
有誰知道怎樣導入Excel何導入Word
SQL code
begin tran ?
set transaction isolation level serializable?
update zjk set zjye =zjye-100 where zjzh ='1234567890'
commit tran ?
以上代碼,使用隔離級別serializable ,即1語句不能讀取已由其他事務修改但尚未提交的數據。
2任何其他事務都不能在當前事務完成之前修改由當前事務讀取的數據。
3在當前事務完成之前,其他事務不能使用當前事務中任何語句讀取的鍵值插入新行。
參考http://msdn.microsoft.com/zh-cn/express/ms173763(SQL.90).aspx
加個rowversion字段,每當數據被修改時,此字段會被UPDATE,?
保存時,判斷記錄是否已經被修改。
又來了,,我問的是解決方案,,不是技術,,,
用7樓的方案就行了,
查詢不鎖,進一步確認時臨時鎖,確認買客戶交錢后更新已售,否則取消鎖
你的問題跟火車票不太一樣的。
對于你的問題,需要解決的是如何處理更新沖突
傳統方式,都是用 update XXXX set xxx where 主鍵=XXX
而使用沖突檢查,則需要用 update XXXX set xxx where 主鍵=XXX and 修改過的字段1=原始值 and 修改過的字段2=原始值……
如果update沒有更新數據,則這條數據不是被其它用戶修改了,就是被刪除了
看來LZ沒有做過實際案例啊,現在我給你透露下實際售票系統中的一個方案例子:?
? 首先沒有那么復雜的鎖,實際應用會盡量從業務角度考慮避免沖突:?
? 實際售票系統是這樣:?
? ? ? ? ? 1.售票中,"座位號" 才是競爭資源;?
? ? ? ? ? 2.售票中,查看票是不發生鎖號的.?
? ? ? ? ? 3.售票中,有個選票(選座位號)的動作,選座位號確定時,才發生鎖號(即鎖住改作為號,即使這鎖號,也只是修改標記,表示自己暫時鎖住);?
? ? ? ? ? 4.等…
關鍵是第三步。我理解買票的時候雖然外面只是一個買入鍵的敲擊動作,但后臺應該是分為1、鎖定當前記錄,2、鎖定成功后修改該票屬性 兩個動作的。只有第一個動作成功,才能做第二個動作。
我傾向于不是用SQL語句來鎖住某行,而是在該行有某字段,修改成功就表示鎖定。鎖表對性能有影響。
我也覺得應該是第三步,,但我細節我不贊成,,我認為,選票時,鎖定該記錄(不一定非要用鎖,可以加一個字段鎖定,此時將它改為鎖定狀態,)當客戶交錢提交交易完成 時,再改該記錄的已售狀態,當取消交易時,,再把鎖定改為非鎖定狀態,,,不知道理解對沒
這個問題也遇到過
如果不用鎖,,去改鎖定字段時,好像也有問題,,當去修改鎖定字段為鎖定狀態時,,此時要是機了重啟了,,那不是一直在鎖定
? "如果不用鎖,,去改鎖定字段時,好像也有問題,,當去修改鎖定字段為鎖定狀態時,,此時要是機了重啟了,,那不是一直在鎖定"
說的沒錯,既然是兩階段提交,自然有可能發生意外在中間過程中,
象你說的中途死機了,這個需要解決的,實際中當然會考慮周全的,有另外解決之道.
所以說,這是個工程,有系列問題要解決.?
如果是死機,可以有方案解決(這個可以自己考慮,各公司可能策略不同),簡單的方法是, 客戶端有緩存日志記錄,如果死機,啟動的時候,自然會知道上次未完成的事情; 當然,如果有好方案也可以在后臺來解決.總之這個就很多途徑.
SQL code
rowversion 字段
在更新前獲取該字段的值,更新是在比較該值是否相當。OK。
似乎也可以理解為事物的ID號。
七樓的又來了,,能不能留個QQ號嘛,,,我想知道細節,,,,
不知道 '伽楠居士' 是研究,還是要開發實際業務系統.
? ?QQ:16258699 (不一定實時都在)
開發實際的業務系統
合格各方的后
1、查詢時不需要鎖;
2、執行時需要驗證,可在一個事務中處理;
即真正需要解決的是在執行階段,表象為:
查詢的時候,票還在,出票瞬間,可能已經沒有票了,即交易不成功。
售票系統最好不要加鎖,耗資源且出了異常需要專門處理(手動釋放鎖)
設計多一個標志字段,在“當用戶點修改時”,讀出數據(讀未標志記錄)同時修改標志,表示“我正在修改這條記錄,其它人不能讀”
如果編輯后保存,保存就可以了
如果編輯后取消,將標志改回,表示“我放棄這條記錄,其它人可以讀”
這種標志是常用的設計
http://jone33.download.csdn.net/ ? 資源不錯,文檔很多。
謝謝大家,,結了,
========
數據庫 事務并發控制
事務是一個邏輯工作單元,SQL Server 2005 提供了幾種自動的可以通過編程來完成的機制,包括事務日志、SQL事務控制語句,以及事務處理運行過程中通過鎖定保證數據完整性的機制。當用戶對數據庫并發訪問時,為了確保事務完整性和數據庫一致性,需要使用鎖定。事務和鎖是兩個緊密聯系的概念。通過事務、批和鎖的使用,還可以監測系統,以及優化物理數據庫。作業是一種多步執行的任務。本章主要介紹 SQL Server 2005數據庫系統的事務和鎖的基本概念,事務、批、鎖的創建和使用,通過事務、批、鎖監測系統和優化物理數據庫的操作,以及作業的設置。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?12.1 事物的基本概念和SQL Server 2005事物處理
事務和存儲過程類似,由一系列T-SQL語句組成,是 SQL Server 2005系統的執行單元。本節主要介紹 SQL Server 2005中事務的概念,以及事務的創建、使用。
12.1.1 事務概述
關系型數據庫有4個顯著的特征:安全性、完整性、檢測性和并發性。數據庫的安全性就是要保證數據庫數據的安全,防止未授權用戶隨意修改數據庫中的數據,確保數據的安全。完整性是數據庫的一個重要特征,也是保證數據庫中的數據切實有效、防止錯誤、實現商業規則的一種重要機制。在數據庫中,區別所保存的數據是無用的垃圾還是有價值的信息,主要是依據數據庫的完整性是否健全,即實體完整性、域完整性和參考完整性。對任何發現影響系統性能的因素和瓶頸,采取切合實際的策略,解決問題,提高系統的性能。并發性是用來解決多個用戶對同一數據進行操作時的問題。特別是對于網絡數據庫來說,這個特點更加突出。提高數據庫的處理速度,單單依靠提高計算機的物理速度是不夠的,還必須充分考慮數據庫的并發性問題,提高數據庫并發性的效率。
那么如何保證并發性呢?在 SQL Server 2005中,通過使用事務和鎖機制,可以解決數據庫的并發性問題。
在 SQL Server 2005中,事務要求處理時必須滿足ACID原則,即原子性(A)、一致性(C)、隔離性(I)和持久性(D)。
原子性:原子性也稱為自動性,是指事務必須執行一個完整的工作,要么執行全部數據的操作,要么全部不執行。
一致性:一致性是指當事務完成時,必須所有的數據具有一致的狀態。
隔離性
隔離性:也稱為獨立性,是指并行事務的修改必須與其他并行事務的修改相互獨立。一個事務處理數據,要么是其他事務執行之前的狀態,要么是其他事務執行之后的狀態,但不能處理其他正在處理的數據。
持久性
持久性:是指當一個事務完成之后,將影響永久性地存于系統中,即事務的操作將寫入數據庫中。
事務的這種機制保證了一個事務或者提交后成功執行,或者提交后失敗回滾,二者必居其一,因此,事務對數據的修改具有可恢復性,即當事務失敗時,它對數據的修改都會恢復到該事務執行前的狀態。而使用一般的批處理,則有可能出現有的語句被執行,而另一些語句沒有被執行的情況,從而有可能造成數據不一致。
事務開始之后,事務所有的操作都陸續寫到事務日志中。這些任務操作在事務日志中記錄一個標志,用于表示執行了這種操作,當取消這種事務時,系統自動執行這種操作的反操作,保證系統的一致性。系統自動生成一個檢查點機制,這個檢查點周期地發生。檢查點的周期是系統根據用戶定義的時間間隔和系統活動的頻度由系統自動計算出來的時間間隔。檢查點周期地檢查事物日志,如果在事務日志中,事務全部完成,那么檢查點將事務提交到數據庫中,并且在事務日志中做一個檢查點提交標記。如果在事務日志中,事務沒有完成,那么檢查點將事務日志中的事務不提交到數據庫中,并且在事務日志中做一個檢查點未提交標記。
12.1.2 事務的類型
根據事務的設置、用途的不同,SQL Server 2005將事務分為多種類型。
1. 根據系統的設置分類
根據系統的設置,SQL Server 2005將事務分為兩種類型:系統提供的事務和用戶定義的事務,分別簡稱為系統事務和用戶定義事務。
(1)系統事務
系統提供的事務是指在執行某些語句時,一條語句就是一個事務。但是要明確,一條語句的對象既可能是表中的一行數據,也可能是表中的多行數據,甚至是表中的全部數據。
因此,只有一條語句構成的事務也可能包含了多行數據的處理。
系統提供的事務語句如下:
ALTER TABLE 、CREATE、DELETE、DROP、FETCH、GRANT、INSERT、OPEN、REBOKE、SELECT、UPDATE、TRUNCATE TABLE
這些語句本身就構成了一個事務。
例12-1使用CREATE TABLE創建一個表。
CREATE TABLE student
? ? ? ? ? ? (id CHAR(10),
? ? ? ? ? ? name CHAR(6),
? ? ? ? ? ? sex CHAR(2)
? ? ? ? ? ? )
說明:這條語句本身就構成了一個事務。這條語句由于沒有使用條件限制,那么這條語句就是創建包含3個列的表。要么創建全部成功,要么全部失敗。
(2)用戶定義事務
在實際應用中,大多數的事務處理采用了用戶定義的事務來處理。在開發應用程序時,可以使用BEGIN TRANSACTION語句來定義明確的用戶定義的事務。在使用用戶定義的事務時,一定要注意事務必須有明確的結束語句來結束。如果不使用明確的結束語句來結束,那么系統可能把從事務開始到用戶關閉連接之間的全部操作都作為一個事務來對待。事務的明確結束可以使用兩個語句中的一個:COMMIT語句和ROLLBACK語句。COMMIT語句是提交語句,將全部完成的語句明確地提交到數據庫中。ROLLBACK語句是取消語句,該語句將事務的操作全部取消,即表示事務操作失敗。
還有一種特殊的用戶定義的事務,這就是分布式事務。例12-1事務是在一個服務器上的操作,其保證的數據完整性和一致性是指一個服務器上的完整性和一致性。但是,如果一個比較復雜的環境,可能有多臺服務器,那么要保證在多臺服務器環境中事務的完整性和一致性,就必須定義一個分布式事務。在這個分布式事務中,所有的操作都可以涉及對多個服務器的操作,當這些操作都成功時,那么所有這些操作都提交到相應服務器的數據庫中,如果這些操作中有一個操作失敗,那么這個分布式事務中的全部操作都將被取消。
2. 根據運行模式分類
根據運行模式,SQL Server 2005將事務分為4種類型:自動提交事務、顯示事務、隱式事務和批處理級事務。
(1)自動提交事務
自動提交事務是指每條單獨的語句都是一個事務。
(2)顯式事務
顯式事務指每個事務均以BEGIN TRANSACTION語句顯式開始,以COMMIT或ROLLBACK語句顯示結束。
(3)隱式事務
隱式事務指在前一個事務完成時新事務隱式啟動,但每個事務仍以COMMIT或ROLLBACK語句顯式完成。
(4)批處理級事務
該事務只能應用于多個活動結果集(MARS),在MARS會話中啟動的T-SQL顯式或隱式事務變為批處理級事務。當批處理完成時,沒有提交或回滾的批處理級事務自動由SQL Server語句集合分組后形成單個的邏輯工作單元。
3. 事務處理語句
BEGIN TRANSAVTION語句。
COMMIT TRANSACTION語句。
ROLLBACK TRANSACTION語句。
SAVE TRANSACTION語句。
(1)BEGIN TRANSECTION 語句
BEGIN TRANSACTION?語句定義渀個顯式本地事務的起點,即事務纄開始。其語法格式為:
b?gIN {??AN|T????сGTM_?}
[{t?an?actio?_?amu 0X??хRLIN? "mailuo:|àtran_nam?_?a?i?b聬e" ? ?聼@t?an_n?me_vasiible}
{WI?? MARK[‘le?cri?tin’}}
]??]
說昞゙
T?A?SAC?ION關鍵字可仧縮寫TRAN?*Trcnsac|恩on_namg虧務唍,PTREN_?EME_warieble是用戶定義盄?含有敨事勡名秴的變量,該變量必頓是字符數據類型?????X耠?ARK指定在查志中標記事?,d?skrmp?ion是描述該栗記的字符串?
(2)COMMIT UR?N[聉CTIO??誤句
C_MOIT ?RANSKC?MON語句標志一個爐功的隱緶事務樞顯式享嚡皌結束。啶語法格式人:
COMMIU{TRA??TSAN?ACTION}?tò??sact?on?nem?|??ran_na?e_?arkab?補?]???]
誒明:僅當事務被引用所有數據的鄻輯都正籮時,T-SQL語句才庴發出COMMIT"T?ANS?C?IO?(命濾あ當在嵍套事務中使用時,妅部事務皤提交并不釋放資澐或使其修改成為縸久修改?只有在提令了外部事務曠,數歮修改扭?有永久悧,而且資源捍會被釋放。當A@U?aN[O?NT?大侎1痶,每?一個CMMIT ?TRANSACT?ON 命仦只會使@@TR?nK?U?T(按1逳凱瀃當A@?VANC?UNTY0 最終逓?伺0時,將提交整個外部些務?
(3)VOLMCA?K "TRANSCCtIO^ 語句
?OьLт?C??`TRAю?ACT?ON! 語埥將顯示事務或隱藏事務皔起點戶事務內皌某個保存點,它也標志七個庋務盄結束。其語泗格彏如下:??O??BICK?Р?TRA??TRANsA?TíON}??tra?sakti?n??a?e|@vrao_n?me_varmafle?s??epo?~t?name|@savepoi??variable][??
說明:?OL??A?K ?VRANSA?TIO^0清除自事劣皅起點或到某丫保存點所有數據修敹。它還釋放由事務控制的資源。Sq?epoi?t_name是S??E !?RC?SA??I?NР 語句中的sawepoint_oame。當條件回滾庖只彳哭事務的一郪分時<可以使甪óav??oi???nameㄒсsaw?po?nt?聶ari?cle港用戶實義的、包含朩效保存點名稱的變駏的唍稱-忕駐是字符敺據類型。儍?AW?d Tò?NS?C\ION語寥
SAVE)(T?ANSACT??~語句在事務內設置保存點。其語法格式為:
SAVE ?{TVAN ??TRQOSAC\I?^]{?avepo?nt??am?|A?avepoint_??riable}[;y
說明:用爺可以在溟務內設置保存點或標記?保存熹可?實義在挏杣件受涍矒個介助的乀部切后,該事犡可以迖回的一個住置〆如果將事務回滾匰保存碹,則根據需覇必頓完戒其廗噩余皤T-SQR!迭句和C聏M?IV TRANSACTKON 語句-或者必須逞過將事務回滛到起始炻完全取消事嚡。若要取涉整個例務,請用R?MNB?CK TR?N?aCTI?N t胲ansact}on?na?mР語句。違將撥消事務的所朋語叭和過程。聓av?ro?nt??a??是分配給忝存猶的名稱も@savetoént_variable包咫有效保存炻名稱的瞨戶定義變量的唍秱。
供1′?′ 寚義丄個事務,帆扈有鑉濮了耳號?筋皆學生的嬆杰動1?分,并毐交該事務。
D??NARE?@t?na?gaK?IR(10)
SE? @t_n?me=’ad??s?o?e’肝BE?IN S HYPERLINKР"ma?lt???RANS??TiON@??nc?e"!!?UvANS??TIoN@t_name?UpEATE成績表
SET 分數=切數+10
WшERE耠課稏號=3?O
CO?MI? TRANSQ??ION @t_n??g
g?$
說明:漬例使甬0B?聇IN?Tz?NSA\KO? ?定義了一為事務名為 a?d_score的事務,之后使用C?Mō]?"?RANWAC?IO? 提交,即行該事務,將所有學生瞅分敲勱18分〢
徛q?=3定義丂個事務,向庫存零仾表中添加一潡辴錄-并設置忝存碹。然后再剠除該記錄,幷回滺到介務盄保存點,提交迥事厡。
B聅?IN ???ANSA?TiN0
I?_EST ??NTO數杮庫雷件表-VAьUES(?6007’,?辺?釘’,100l‘黑’,20)??AVE ?T?ANSICTI? s?vepoin?(-EEL?TE?FRoM 庫孫零件表
WHERE 零件編號=‘20007’
ROLLBACK ?TRANSACTION savepoint
COMMIT ?TRANSACTION
GO
說明:本例使用BEGIN TRANSACTION定義了一個事務,向表添加一條記錄,并設置保存點savepoint.之后再刪除該記錄,并回滾到事務的保存點savepoint處,使用COMMIT TRANSACTION 提交。結果該記錄沒有刪除。
例12-4定義一個事務,向學生表中添加記錄。如果添加成功,則給每個分數加10分。否則不操作。
BEGIN ?TRAN
INSERT INTO ?學生表
VALUES(‘234’,‘張’,‘男’,‘1980-10-28’,‘1’,‘3’,null)
IF @@ error=0
? ?BEGIN
PRINT ‘添加成功!’
UPDATE 成績表
SET分數=分數+10
WHERE 學號=111
COMMIT TRAN
END
? ?ELSE
BEGIN
? PRINT‘添加失敗!’
? ROLLBACK ?TRAN
END
12.1.3 事務和批
如果用戶希望或者整個操作完成,或者什么都不做,這時解決問題的方法就是將整個操作組織成一個簡單的事務處理,稱為批處理或批。
例12-5將多個操作定義為一個事務。
BEGIN ?TRANSACTION
UPDATE 成績表
SET 分數=分數+10
WHERE 課程號=5
INSERT INTO 學生表(學號,姓名)
VALUES(20123,‘張全’)
DELETE FROM 課程表
WHERE 課程表
WHERE 課程名 LIKE ‘數%’
COMMIT TRANSACTION
說明:本例將多個SQR操作定義為一個事務,這時就形成了一個批處理,要么全部執行,要么都不執行。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?12.2 并發控制的基本概念和SQL Server 2005的并發控制機制
鎖就是防止其他事務訪問指定資源的手段。鎖是實現并發控制的主要方法,是多個用戶能夠同時操縱同一個數據庫的數據而不發生數據不一致現象的重要保障。
12.2.1 鎖概述
一般來說,鎖可以防止臟讀、不可重復讀和幻覺讀。臟讀就是指當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據,那么另外嚴格事務讀到這個數據就是臟數據,依據臟數據所做的操作可能是不正確的。不可重復讀是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,則第一個事務兩次讀到的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此,稱為不可重復讀。幻覺讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還沒有修改的數據行,就好像發生了幻覺一樣。
鎖是防止其他事務訪問指定的資源控制、實現并發控制的一種手段。為了提高系統的性能、加快事務的處理速度、縮短事務的等待時間,應該使鎖定的資源最小化。為了控制鎖定的資源,應該首先了解系統的空間管理。在SQR SERVER 2005中,最小空間管理單位是頁,一個頁有8KB。所有的數據、日志、索引都存放在頁上。另外,使用頁有一個限制,這就是表中的一行數據必須在同一個頁上。另外,使用頁有一個限制,這就是表中的一行數據必須在同一個頁上,不能跨頁。頁上面的空間管理單位是簇,一個簇是8個連續的頁。表和索引的最小占用單位是簇。數據庫是有一個或多個表或者索引組成,即有多個簇組成。
12.2.2 鎖的模式
數據庫引擎使用不同的鎖定資源,這些鎖模式確定了并發事務訪問資源的方式。根據鎖定資源方式的不同,SQR SERVER 2005 提供了4種鎖模式:共享鎖、排他鎖、更新鎖,意向鎖。
1. 共享鎖
共享鎖也稱為S鎖,允許并行事務讀取同一種資源,這時的事務不能修改訪問的數據。當使用共享鎖鎖定資源時,不允許修改數據的事務訪問數據。當讀取數據的事務讀完數據之后,立即釋放所占用的資源。一般地,當使用SELECT 語句訪問數據時,系統自動對所訪問的數據使用共享鎖鎖定。
2. 排他鎖
對于那些修改數據的事務,例如,使用INSERT、UPDATE、DELETE語句 ,系統自動在所修改的事務上放置排他鎖。排他鎖也稱X鎖,就是在同一時間內只允許一個事務訪問一種資源,其他事務都不能在有排他鎖的資源上訪問。在有排他鎖的資源上,不能放置共享鎖,也就是說,不允許可以產生共享鎖的事務訪問這些資源。只有當產生排他鎖的事務結束之后,排他鎖鎖定的資源才能被其他事務使用。
3. 更新鎖
更新鎖也稱為U鎖,可以防止常見的死鎖。在可重復讀或可序化事務中,此事務讀取數據,獲取資源的共享鎖,然后修改數據。此操作要求鎖轉換為排鎖。如果兩個事務獲取了資源上的共享模式鎖,然后試圖同時更新數據,則一個事務嘗試將鎖轉換為排他鎖。共享模式到排他鎖的轉換必須等待一段時間,因為一個事務的排他鎖與其他事務的共享模式鎖不兼容,發生鎖等待。第二個事務試圖獲取排他鎖以進行更新。由于兩個事務都要轉換為排他鎖,并且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。
若要避免這種潛在的死鎖問題,請使用更新鎖。一次只有一個事務可以獲得資源的更新鎖。如果事務修改資源,則更新鎖轉換為排他鎖。
4. 意向鎖
數據庫引擎使用意向鎖來保護共享鎖或排他鎖放置在鎖層次結構的底層資源上。之所以命名為意向鎖,是因為在較低級別鎖前可獲取它們,因此,會通知意向將鎖放置在較低級別上。意向鎖有兩種用途:
防止其他事務以會使較低級別的鎖無效的方式修改較高級別資源。
提高數據庫引擎在較高的粒度級別檢測鎖沖突的效率。
意向鎖又分為意向共享鎖(IS)、意向排他鎖(IX)、以及意向排他共享鎖(SIX)。意向共享鎖表示讀低層次資源的事務的意向,把共享鎖放在這些單個的資源上。意向排他鎖表示修改低層次的事務的意向,把排他鎖放在這些單個資源上。意向排他鎖包括意向共享鎖,它是意向共享鎖的超集。使用意向排他的共享鎖表示允許并行讀取頂層資源的事務的意向,并且修改一些低層次的資源,把意向排他鎖這些單個資源上。例如,表上的一個使用意向排他的共享鎖把共享鎖放在表上,允許并行讀取,并且把意向排他鎖放在剛要修改的頁上,把排他鎖放在修改的行上。每一個表一次只能有一個使用意向排他的共享鎖因為表級共享鎖阻止對表的任何修改。使用意向排他的共享鎖和意向排他鎖的組合。
12.2.3 鎖的信息
鎖兼容性控制多個事務能否同時獲取同一資源上的鎖。如果資源已被另一事務鎖定,則,僅當請求鎖的模式與現有鎖的模式兼容時,才會授予新的鎖請求。如果請求鎖的模式與現有的模式不兼容,則請求新鎖的事務將等待釋放現有鎖或等待鎖超時間隔過期。例如,沒有與排他鎖兼容的鎖模式。如果具有排他鎖,則在釋放排他鎖之前,其他事務均無法獲取該資源的任何類型(共享、更新或排他)的鎖。另一種情況是,如果共享鎖已應用到資源,則即使第一個事務尚未完成,其他事務也可以獲取該項的共享鎖或更新鎖。但是,在釋放共享鎖之前,其他事務無法獲取排他鎖。
用戶可以通過使用SQL SERVER 2005的SQL SERVER PROFILER,指定用來捕獲有關跟蹤中鎖事件的信息的鎖事件類別。還可以在系統監視器中,從鎖對象指定計數器來監視數據庫引擎實例中的鎖級別。
在SQR ?SERVERN ?PROFILER中查看系統鎖定信息時,首先啟動SQR ? SERVER ?PROFILER,其窗口如圖12-1所示。
圖12-1 ?SQL Server Profiler ?窗口
選擇系統菜單“文件”—— “新建跟蹤”選項,新建一個跟蹤事件,連接到服務器,如圖12-2所示。
圖12-2連接服務器
連接成功,設置根據事件屬性。在“跟蹤屬性”對話框的“常規”選項卡中,用戶可以設置跟蹤名稱、使用模板,以及啟用跟蹤停止時間和將跟蹤存儲到指定文件,如圖12-3所示。
圖12-3 跟蹤屬性 對話框的常規選項卡
還可以將跟蹤保存到指定表。在“跟蹤屬性”對話框的“事件選擇”選項卡中,用戶可以設置跟蹤的事件以及事件的列,如圖12-4所示。
圖12-4跟蹤屬性對話框的事件選擇選項卡
設置完畢,在SQL Server Profiler中顯示跟蹤事件,如圖12-5所示。
圖 12-5 跟蹤事件的顯示
同時,在SSMS的對象資源管理器中,系統將新建一個新表,即設置的保存到表。打開該表,顯示用戶設置跟蹤的事件以及事件的列。
為了和SQL Server兼容,還可以使用sys.dm_tran_locks動態管理視圖來替代sp_lock系統存儲過程。
12.2.4 死鎖及處理
在事務鎖的使用過程中,死鎖是一個不可避免的現象。在下列兩種情況下,可以發生死鎖。
第一種情況是,當兩個事務分別鎖定了兩個單獨的對象,這時每一個事務都有要求在另外一個事務鎖定的對象上獲得一個鎖,因此第一個事務都有必須等待另一個釋放占有的鎖,這時就發生了死鎖,這種死鎖是最典型的死鎖形式。
死鎖的第二種情況是,當在一個數據庫中。有若干個長時間運行的事務執行并行的操作,當查詢分析器處理一種非常復雜的查詢例如連接查詢時,那么;由于不能控制處理的順序,有可能發生死鎖現象。
當發生了死鎖現象時, 除非某個外部進程斷開死鎖,否則死鎖中的兩個事務都將無期等待下去。SQL Server 2005的SQL Server Database Engine自動檢測SQL Server中的死鎖循環。數據庫引擎選擇一個會話作為死鎖犧牲,然后終止當前事務(出現錯誤)來打斷死鎖。如果監視器檢測到循環依賴關系,通過自動取消其中一個事務來結束死鎖。處理時間長的事務具有較高的優先級,處理時間較短的事務具有較低的優先級。在發生沖突時,保留優先級高的事務,取消優先級的事務。
用戶可以使用SQL Server Profiler確定死鎖的原因。當SQLServer中某組資源的兩個或多個線程或進程之間存在的依賴關系時,將會發生死鎖。使用SQL Server Profiler,可以創建記錄、重播和顯示死鎖事件的跟蹤以進行分析。
若要跟蹤死鎖事件,請將Deadlock graph事件類添加到跟蹤。可以通過下列任一方法進行提取:
在配置跟蹤時,使用“事件提取設置”選項卡。請注意,只有在“事件選擇“選項卡上選擇了Deadlock graph事件,才會出現此選項卡。
也可以使用“文件“菜單中的”提取SQL Server事件“選項,或者通過鼠標右鍵擊特定事件并選擇”提取事件數據“,來提取并保存各個事件。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.3 數據庫優化
一個數據庫系統的性能依賴于組成這些系統的數據庫中物理設計結構的有效配置。這些物理設計結構包括索引、聚集索引、索引視圖和分區等,其目的在于提高數據庫的性能和可管理性。SQL Server 2005提供了一套綜合的工具,用于優化物理數據庫的設計,其中數據庫引擎優化顧問,是分析一個或多個數據庫上工作負荷(對要做出化的數據庫招待的一組T-SQL語名句)的性能效果的工具。
本節主要介紹數據庫引擎優化顧問的使用。
12.3.1 數據庫引擎優化顧問概述
數據庫引擎優化顧問是一種工具,用于分析在一個或多個數據庫中運行的工作負荷的性能效果。工作負荷是對在優化的數據庫招待的一組T-SQL語句。分析數據庫的工作負荷效果后,數據庫引擎優化顧問會提供在SQL Server 2005 數據庫中添加、刪除或修改物理設計結構的建議。這些物理性能結構包括聚集索引、非聚集索引、索引視圖和分區。實現這些結構之后,數據庫引擎優化顧問使查詢處理器能夠用最短的時間性執行工作負荷任務。
12.3.2 數據庫引擎優化顧問的使用
數據庫引擎優化顧問提供了兩種使用方式:
圖形界面。用于優化數據庫、查看優化建議和報告的工具。
命令行實用工具程序dta.exe。用于實現數據庫引擎優化顧問在軟件程序和腳本方面的功能。
本節只介紹圖形界面優化數據庫,需要啟動數據庫引擎優化顧問。首先連接到服務器,如圖12-6所示。
圖12-6連接服務器
連接成功后,進入數據庫引擎優顧問。如圖12-7所示。
圖12-7數據庫引擎優顧問
用戶可以在“會話框”中設置數據庫優化設置。選擇工作負荷文件,即由SQL Server Proriler創建的事件文件。選擇需要優化的數據庫。如圖12-8所示。
圖12-8選擇需要優化的數據庫
選擇系統菜單“操作”→“開始分析”選項,系統自動對數據庫進行優化分析操作。優化分析結束,在“會話框”中多出了3個選項:進度、建議、和報告。顯示優化分析的進度信息,建議信息和優化報告信息。
用戶還可以選擇系統菜單“文件”→“新建會話”選項,新建一個會話,優化其他的數據庫。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.4 小結
結合第1章DBMS的DCL數據庫的安全性控制功能,本章講解事物的基本概念和SQL Server 2005事物處理和并發控制的基本概念,包括封鎖、封鎖協議、活鎖、死鎖等概念;講解SQL Server 2005的并發控制機制。
========
數據庫 并發控制 常見鎖
封鎖 (數據庫)
封鎖是一項用于多用戶同時訪問數據庫的技術,是實現并發控制的一項重要手段,能夠防止當多用戶改寫數據庫時造成數據丟失和損壞。當有一個用戶對數據庫內的數據進行操作時,在讀取數據前先鎖住數據,這樣其他用戶就無法訪問和修改該數據,直到這一數據修改并寫回數據庫解除封鎖為止。
樂觀并發控制(樂觀鎖)
在關系數據庫管理系統里,樂觀并發控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種并發控制的方法。它假設多用戶并發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分數據。在提交數據更新之前,每個事務會先檢查在該事務讀取數據后,有沒有其他事務又修改了該數據。如果其他事務有更新的話,正在提交的事務會進行回滾。樂觀事務控制最早是由孔祥重(H.T.Kung)教授提出[1]。
樂觀并發控制多數用于數據爭用不大、沖突較少的環境中,這種環境中,偶爾回滾事務的成本會低于讀取數據時鎖定數據的成本,因此可以獲得比其他并發控制方法更高的吞吐量。
目錄
1 樂觀并發控制的階段
2 優點與不足
3 相關條目
4 參考文獻
5 外部鏈接
樂觀并發控制的階段
樂觀并發控制的事務包括以下階段:[來源請求]
讀取:事務將數據讀入緩存,這時系統會給事務分派一個時間戳。
校驗:事務執行完畢后,進行提交。這時同步校驗所有事務,如果事務所讀取的數據在讀取之后又被其他事務修改,則產生沖突,事務被中斷回滾。
寫入:通過校驗階段后,將更新的數據寫入數據庫。
悲觀并發控制(悲觀鎖)
在關系數據庫管理系統里,悲觀并發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種并發控制的方法。它可以阻止一個事務以影響其他用戶的方式來修改數據。如果一個事務執行的操作都某行數據應用了鎖,那只有當這個事務把鎖釋放,其他事務才能夠執行與該鎖沖突的操作。
悲觀并發控制主要用于數據爭用激烈的環境,以及發生并發沖突時使用鎖保護數據的成本要低于回滾事務的成本的環境中。
========
多種數據庫的并發控制比較
多種數據庫的并發控制比較
內容:
比較的ORACLE INFORMIX DB2 SYBASE MSSQL等的并發控制機制。比較分析悲觀與樂觀并發控制機制的異同。
引言:
l ? ? ? 在關系數據庫(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢復和交易單位為一個事務(Transactions),事務具有ACID(原子性,一致性,隔離性和永久性)特征。關系數據庫為了確保并發用戶在存取同一數據庫對象時的正確性(即無丟失更新、可重復讀、不讀"臟"數據,無"幻像"讀),數據庫中引入了并發(鎖)機制。基本的鎖類型有兩種:排它鎖(Exclusive locks記為X鎖)和共享鎖(Share locks記為S鎖)。
l ? ? ? 排它鎖:若事務T對數據D加X鎖,則其它任何事務都不能再對D加任何類型的鎖,直至T釋放D上的X鎖;一般要求在修改數據前要向該數據加排它鎖,所以排它鎖又稱為寫鎖。
l ? ? ? 共享鎖:若事務T對數據D加S鎖,則其它事務只能對D加S鎖,而不能加X鎖,直至T釋放D上的S鎖;一般要求在讀取數據前要向該數據加共享鎖,所以共享鎖又稱為讀鎖。
相關解釋
l頁:以磁盤頁面(disk pages)為單位存儲數據。一個磁盤頁面包含一個或多個記錄。
l鍵字級:Informix(在一定情況下,數據庫服務器需要鎖一個不存在的記錄。它的效果相當于在記錄將要存在的地方放一個鎖。當表使用記錄鎖時,對假想的記錄使用鍵字鎖。當表使用頁級鎖時,含有或可能含有鍵字的索引頁將被設置鍵級鎖)。MSSQL(索引中的行鎖。用于保護可串行事務中的鍵范圍)。
l擴展盤區:相鄰的八個數據頁或索引頁構成的一組。
l表空間:DB2 的表空間按管理方式分為兩種:系統管理空間和數據庫管理空間。 按類型分為:規則表空間、長整數表空間、系統臨時表空間、用戶臨時表空間 。其中長整數表空間只能是DMS的。規則表空間中包含用戶數據的表。默認用戶表空間名為USERSPACE1,索引也存在規則表空間中,另外系統目錄表也放在規則表空間中。
?
DB2數據庫表鎖的模式?
幾種表鎖的模式進一步闡述:
lIS、IX、SIX方式用于表一級并需要行鎖配合,他們可以阻止其他應用程序對該表加上排它鎖。
l如果一個應用程序獲得某表的IS鎖,該應用程序可獲得某一行上的S鎖,用于只讀操作,同時其他應用程序也可以讀取該行,或是對表中的其他行進行更改。
l如果一個應用程序獲得某表的IX鎖,該應用程序可獲得某一行上的X鎖,用于更改操作,同時其他應用程序可以讀取或更改表中的其他行。
l如果一個應用程序獲得某表的SIX鎖,該應用程序可以獲得某一行上的X鎖,用于更改操作,同時其他應用程序只能對表中其他行進行只讀操作。
幾種表鎖的模式進一步闡述:
lS、U、X和Z方式用于表一級,但并不需要行鎖配合,是比較嚴格的表加鎖策略。
l如果一個應用程序得到某表的S鎖。該應用程序可以讀表中的任何數據。同時它允許其他應用程序獲得該表上的只讀請求鎖。如果有應用程序需要更改讀該表上的數據,必須等S鎖被釋放。
l如果一個應用程序得到某表的U鎖,該應用程序可以讀表中的任何數據,并最終可以通過獲得表上的X鎖來得到對表中任何數據的修改權。其他應用程序只能讀取該表中的數據。U鎖與S鎖的區別主要在于更改的意圖上。U鎖的設計主要是為了避免兩個應用程序在擁有S鎖的情況下同時申請X鎖而造成死鎖的。
l如果一個應用程序得到某表上的X鎖,該應用程序可以讀或修改表中的任何數據。其他應用程序不能對該表進行讀或者更改操作。
l如果一個應用程序得到某表上的Z鎖,該應用程序可以讀或修改表中的任何數據。其他應用程序,包括未提交讀程序都不能對該表進行讀或者更改操作。
lIN鎖用于表上以允許未提交讀這一概念。
DB2數據庫行鎖的模式
?
DB2數據庫表鎖的相容矩陣
?
DB2數據庫行鎖的相容矩陣
?
DB2中各SQL語句產生表鎖的情況(假設缺省的隔離級別為CS):
?
DB2鎖的升級 (1)
l每個鎖在內存中都需要一定的內存空間,為了減少鎖需要的內存開銷,DB2提供了鎖升級的功能。鎖升級是通過對表加上非意圖性的表鎖,同時釋放行鎖來減少鎖的數目,從而達到減少鎖需要的內存開銷的目的。鎖升級是由數據庫管理器自動完成的,有兩個數據庫的配置參數直接影響鎖升級的處理:
llocklist--在一個數據庫全局內存中用于鎖存儲的內存。單位為頁(4K)。
lmaxlocks--一個應用程序允許得到的鎖占用的內存所占locklist大小的百分比。
l鎖升級會在這兩種情況下被觸發:
l某個應用程序請求的鎖所占用的內存空間超出了maxlocks與locklist的乘積大小。這時,數據庫管理器將試圖通過為提出鎖請求的應用程序申請表鎖,并釋放行鎖來節省空間。
DB2鎖的升級 (2)
l在一個數據庫中已被加上的全部鎖所占的內存空間超出了locklist定義的大小。這時,數據庫管理器也將試圖通過為提出鎖請求的應用程序申請表鎖,并釋放行鎖來節省空間。
l鎖升級雖然會降低OLTP應用程序的并發性能,但是鎖升級后會釋放鎖占有內存并增大可用的鎖的內存空間。
l鎖升級是有可能會失敗的,比如,現在一個應用程序已經在一個表上加有IX鎖,表中的某些行上加有X鎖,另一個應用程序又來請求表上的IS鎖,以及很多行上的S鎖,由于申請的鎖數目過多引起鎖的升級。數據庫管理器試圖為該應用程序申請表上的S鎖來減少所需要的鎖的數目,但S鎖與表上原有的IX鎖沖突,鎖升級不能成功。
l如果鎖升級失敗,引起鎖升級的應用程序將接到一個-912的SQLCODE。在鎖升級失敗后,DBA應該考慮增加locklist的大小或者增大maxlocks的百分比。同時對編程人員來說可以在程序里對發生鎖升級后程序回滾后重新提交事務(例如:if sqlca.sqlcode=-912 then rollback and retry等)。
?
Oracle 多粒度鎖機制介紹
l根據保護對象的不同,Oracle數據庫鎖可以分為以下幾大類:
l(1) DML lock(data locks,數據鎖):用于保護數據的完整性;
l(2) DDL lock(dictionary locks,字典鎖):用于保護數據庫對象的結構(例如表、視圖、索引的結構定義);
l(3) Internal locks 和latches(內部鎖與閂):保護內部數據庫結構;
l(4) Distributed locks(分布式鎖):用于OPS(并行服務器)中;
l(5) PCM locks(并行高速緩存管理鎖):用于OPS(并行服務器)中。
l在Oracle中最主要的鎖是DML(也可稱為data locks,數據鎖)鎖。從封鎖粒度(封鎖對象的大小)的角度看,Oracle DML鎖共有兩個層次,即行級鎖和表級鎖。
?
Oracle的TX鎖行級鎖、事務鎖?
l許多對Oracle不太了解的技術人員可能會以為每一個TX鎖代表一條被封鎖的數據行,其實不然。TX的本義是Transaction(事務)當一個事務第一次執行數據更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE語句進行查詢時,它即獲得一個TX(事務)鎖,直至該事務結束(執行COMMIT或ROLLBACK操作)時,該鎖才被釋放。所以,一個TX鎖,可以對應多個被該事務鎖定的數據行(在我們用的時候多是啟動一個事務,然后SELECT… FOR UPDATE NOWAIT)。
l在Oracle的每行數據上,都有一個標志位來表示該行數據是否被鎖定。Oracle不像DB2那樣,建立一個鏈表來維護每一行被加鎖的數據,這樣就大大減小了行級鎖的維護開銷,也在很大程度上避免了類似DB2使用行級鎖時經常發生的鎖數量不夠而進行鎖升級的情況。數據行上的鎖標志一旦被置位,就表明該行數據被加X鎖,Oracle在數據行上沒有S鎖。
Oracle意向鎖?
l意向鎖的含義是如果對一個結點加意向鎖,則說明該結點的下層結點正在被加鎖;對任一結點加鎖時,必須先對它的上層結點加意向鎖。如:對表中的任一行加鎖時,必須先對它所在的表加意向鎖,然后再對該行加鎖。這樣一來,事務對表加鎖時,就不再需要檢查表中每行記錄的鎖標志位了,系統效率得以大大提高。
l由兩種基本的鎖類型(S鎖、X鎖),可以自然地派生出兩種意向鎖:
l另外,基本的鎖類型(S、X)與意向鎖類型(IS、IX)之間還可以組合出新的鎖類型,理論上可以組合出4種,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不難看出,實際上只有S+IX有新的意義,其它三種組合都沒有使鎖的強度得到提高(即:S+IS=S,X+IS=X,X+IX=X,這里的"="指鎖的強度相同)。所謂鎖的強度是指對其它鎖的排斥程度。
l這樣我們又可以引入一種新的鎖的類型:共享意向排它鎖(Shared Intent Exclusive Lock,簡稱SIX鎖):如果對一個數據庫對象加SIX鎖,表示對它加S鎖,再加IX鎖,即SIX=S+IX。例如:事務對某個表加SIX鎖,則表示該事務要讀整個表(所以要對該表加S鎖),同時會更新個別行(所以要對該表加IX鎖)。
l具有意向鎖的多粒度封鎖方法中任意事務T要對一個數據庫對象加鎖,必須先對它的上層結點加意向鎖。申請封鎖時應按自上而下的次序進行;釋放封鎖時則應按自下而上的次序進行;具有意向鎖的多粒度封鎖方法提高了系統的并發度,減少了加鎖和解鎖的開銷。
Oracle的TM鎖(表級鎖)?
? ??
Oracle數據庫TM鎖小結
?
多粒度封鎖機制的監控?
l快照監控
l事件監控方式
l視圖(Oracle)
v$lock視圖列出當前系統持有的或正在申請的所有鎖的情況
?
v$locked_object視圖列出當前系統中哪些對象正被鎖定
?
總結 (1)
l1.Oracle通過具有意向鎖的多粒度封鎖機制進行并發控制,保證數據的一致性。其DML鎖(數據鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級;DB2也是通過具有意向鎖的多粒度封鎖機制進行并發控制,保證數據的一致性。其DML鎖(數據鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(IS,SIX或IX),其真正的封鎖粒度也是在行級;另外,在Oracle數據庫中,單純地讀數據(SELECT)并不加鎖,這些都提高了系統的并發程度,Oracle強調的是能夠"讀"到數據,并且能夠快速的進行數據讀取。而DB2的鎖強調的是"讀一致性",進行讀數據(SELECT)時會根據不同的隔離級別(RR,RS,CS)而分別加S,IS,IS鎖,只有在使用UR隔離級別時才不加鎖。從而保證不同應用程序和用戶讀取的數據是一致的。
總結(2)
l2. 在支持高并發度的同時,DB2和Oracle對鎖的操縱機制有所不同:Oracle利用意向鎖及數據行上加鎖標志位等設計技巧,減小了Oracle維護行級鎖的開銷,使其在數據庫并發控制方面有著一定的優勢。而DB2中對每個鎖會在鎖的內存(locklist)中申請分配一定字節的內存空間,具體是X鎖64字節內存,S鎖32字節內存(注:DB2 V8之前是X鎖72字節內存而S鎖36字節內存)。
l3. Oracle數據庫中不存在鎖升級,而DB2數據庫中當數據庫表中行級鎖的使用超過locklist*maxlocks會發生鎖升級。
l4. 在Oracle中當一個session對表進行insert,update,delete時候,另外一個session仍然可以從Orace回滾段或者還原表空間中讀取該表的前映象(before image); 而在DB2中當一個session對表進行insert,update,delete時候,另外一個session仍然在讀取該表數據時候會處于lock wait狀態,除非使用UR隔離級別可以讀取第一個session的未提交的值;所以Oracle同一時刻不同的session有讀不一致的現象,而DB2在同一時刻所有的session都是"讀一致"的。
?
SQLServer使用以下資源鎖模式
?
l共享 (S):用于不更改或不更新數據的操作(只讀操作),如 SELECT 語句。
l更新 (U): ? 用于可更新的資源中。防止當多個會話在讀取、鎖定以及隨后可能進行的資源更新時發生常見形式的死鎖。
l排它 (X): ? 用于數據修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時對同一資源進行多重更新。
l意向:用于建立鎖的層次結構。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
l架構:在執行依賴于表架構的操作時使用。架構鎖的類型為:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。
l大容量更新 (BU):向表中大容量復制數據并指定了 TABLOCK 提示時使用。
架構鎖
?
l執行表的數據定義語言 (DDL) 操作(例如添加列或除去表)時使用架構修改 (Sch-M) 鎖。
l當編譯查詢時,使用架構穩定性 (Sch-S) 鎖。架構穩定性 (Sch-S) 鎖不阻塞任何事務鎖,包括排它 (X) 鎖。因此在編譯查詢時,其它事務(包括在表上有排它 (X) 鎖的事務)都能繼續運行。但不能在表上執行 DDL 操作。
大容量更新鎖
l當將數據大容量復制到表,且指定了 TABLOCK 提示或者使用 sp_tableoption 設置了 table lock on bulk 表選項時,將使用大容量更新 (BU) 鎖。大容量更新 (BU) 鎖允許進程將數據并發地大容量復制到同一表,同時防止其它不進行大容量復制數據的進程訪問該表。
?
Sybase鎖的狀態
lSQL SERVER加鎖有三種狀態:
l1)意向鎖(intend)—是一種表級鎖,它表示在一個數據頁上獲得一個S或X鎖的意向。意向鎖可以防止其他事務在該數據頁的表上獲得排它鎖。
l2)阻塞(blocking,簡記blk)—它表明目前加鎖進程的狀態,帶有blk后綴的鎖說明該進程目前正阻塞另一個需要獲得鎖的進程,只有這一進程完成,其他進程才可以進行。
l3)需求鎖(demand)—表示此時該進程企圖得到一個排它鎖。它可以防止在這一表或頁上加過多的S鎖,她表示某一事務是下一個去鎖定該表和該頁的事務。
l需求鎖是一個內部過程,因此用sp_lock是無法看見的。
?
Informix
l鎖的類型 INFORMIX有三種不同類型的鎖。它們在不同的情況下使用。?
1. SHARED鎖?
SHARED鎖只保留對象的可讀性。當鎖存在時,對象不能改變。多個程序可對同個對象加SHARED鎖。?
2. EXCLUSIVE鎖?
只能使單個程序使用。在程序要改變對象時使用。當其他鎖存在時,EXCLUSIVE鎖不能使用。當使用了EXCLUSIVE 鎖后,其他鎖不能用于同一對象。?
3. PROMOTABLE鎖?
實現更新的目的。PROMOTABLE鎖可以放在已經有SHARED鎖的記錄,但不能放在已經有PROMOTABLE鎖和EXCLUSIVE 鎖的地方。當記錄上無其他鎖(含SHARED 鎖)情況下,這時在程序準備改變鎖的記錄時,PROMOTABLE鎖可以提升為EXCLUSIVE鎖。如果在已有SHARED鎖的記錄上設置了PROMOTABLE鎖,在PROMOTABLE鎖可以提升到EXCLUSIVE鎖?
之前需要刪除SHARED 鎖。PROMOTABLE鎖只能在INFORMIX Universal Server中支持。?
========
相關鏈接
http://blog.csdn.net/xiangminjing/article/details/5922325http://www.cnblogs.com/chuncn/archive/2009/04/21/1440233.html
http://www.cnblogs.com/binfire/articles/1689572.html
http://blog.csdn.net/longronglin/article/details/1522561
http://blog.csdn.net/klarclm/article/details/7532454
總結
- 上一篇: IOS操作数据库总结
- 下一篇: GDAL学习总结