日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

数据库并发学习总结

發(fā)布時(shí)間:2025/4/14 数据库 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库并发学习总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

數(shù)據(jù)庫(kù)并發(fā)控制



1. ?在數(shù)據(jù)庫(kù)中為什么要并發(fā)控制?


答:數(shù)據(jù)庫(kù)是共享資源,通常有許多個(gè)事務(wù)同時(shí)在運(yùn)行。當(dāng)多個(gè)事務(wù)并發(fā)地存取數(shù)據(jù)庫(kù)時(shí)就會(huì)產(chǎn)生同時(shí)讀取和/或修改同一數(shù)據(jù)的情況。若對(duì)并發(fā)操作不加控制就可能會(huì)存取和存儲(chǔ)不正確的數(shù)據(jù),破壞數(shù)據(jù)庫(kù)的一致性。所以數(shù)據(jù)庫(kù)管理系統(tǒng)必須提供并發(fā)控制機(jī)制。


2 .并發(fā)操作可能會(huì)產(chǎn)生哪幾類數(shù)據(jù)不一致?用什么方法能避免各種不一致的情況?


答:并發(fā)操作帶來(lái)的數(shù)據(jù)不一致性包括三類:丟失修改、不可重復(fù)讀和讀“臟’夕數(shù)據(jù)。 ( l )丟失修改(lost update ) 兩個(gè)事務(wù) Tl 和T2讀入同一數(shù)據(jù)并修改,T2提交的結(jié)果破壞了(覆蓋了) Tl 提交的結(jié)果,導(dǎo)致 Tl 的修改被丟失。 ( 2 )不可重復(fù)讀( Non 一 Repeatable Read ) 不可重復(fù)讀是指事務(wù) Tl 讀取數(shù)據(jù)后,事務(wù)幾執(zhí)行更新操作,使 Tl 無(wú)法再現(xiàn)前一次讀取結(jié)果。( 3 )讀“臟”數(shù)據(jù)( Dirty Read ) 讀“臟’夕數(shù)據(jù)是指事務(wù) Tl 修改某一數(shù)據(jù),并將其寫回磁盤,事務(wù)幾讀取同一數(shù)據(jù)后, Tl 由于某種原因被撤銷,這時(shí) Tl 已修改過(guò)的數(shù)據(jù)恢復(fù)原值,幾讀到的數(shù)據(jù)就與數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致,則幾讀到的數(shù)據(jù)就為“臟”數(shù)據(jù),即不正確的數(shù)據(jù)。避免不一致性的方法和技術(shù)就是并發(fā)控制。最常用的技術(shù)是封鎖技術(shù)。也可以用其他技術(shù),例如在分布式數(shù)據(jù)庫(kù)系統(tǒng)中可以采用時(shí)間戳方法來(lái)進(jìn)行并發(fā)控制。


3 .什么是封鎖?基本的封鎖類型有幾種?試述它們的含義。


答:封鎖就是事務(wù) T 在對(duì)某個(gè)數(shù)據(jù)對(duì)象例如表、記錄等操作之前,先向系統(tǒng)發(fā)出請(qǐng)求,對(duì)其加鎖。加鎖后事務(wù) T 就對(duì)該數(shù)據(jù)對(duì)象有了一定的控制,在事務(wù) T 釋放它的鎖之前,其他的事務(wù)不能更新此數(shù)據(jù)對(duì)象。封鎖是實(shí)現(xiàn)并發(fā)控制的一個(gè)非常重要的技術(shù)。


基本的封鎖類型有兩種:排它鎖( Exclusive Locks ,簡(jiǎn)稱 x 鎖)和共享鎖 ( Share Locks,簡(jiǎn)稱 S 鎖)。排它鎖又稱為寫鎖。若事務(wù) T 對(duì)數(shù)據(jù)對(duì)象 A 加上 X 鎖,則只允許 T 讀取和修改 A ,其他任何事務(wù)都不能再對(duì) A 加任何類型的鎖,直到 T 釋放 A 上的鎖。這就保證了其他事務(wù)在 T 釋放 A 上的鎖之前不能再讀取和修改 A 。共享鎖又稱為讀鎖。若事務(wù) T 對(duì)數(shù)據(jù)對(duì)象 A 加上 S 鎖,則事務(wù) T 可以讀 A但不能修改 A ,其他事務(wù)只能再對(duì) A 加 S 鎖,而不能加 X 鎖,直到 T 釋放 A 上的 S 鎖。這就保證了其他事務(wù)可以讀 A ,但在 T 釋放 A 上的 S 鎖之前不能對(duì) A 做任何修改。


4 .如何用封鎖機(jī)制保證數(shù)據(jù)的一致性?


答: DBMS 在對(duì)數(shù)據(jù)進(jìn)行讀、寫操作之前首先對(duì)該數(shù)據(jù)執(zhí)行封鎖操作,例如下圖中事務(wù) Tl 在對(duì) A 進(jìn)行修改之前先對(duì) A 執(zhí)行 xock ( A ) ,即對(duì) A 加 x 鎖。這樣,當(dāng)幾請(qǐng)求對(duì) A 加 x 鎖時(shí)就被拒絕,幾只能等待 Tl 釋放 A 上的鎖后才能獲得對(duì) A 的 x 鎖,這時(shí)它讀到的 A 是 Tl 更新后的值,再按此新的 A 值進(jìn)行運(yùn)算。這樣就不會(huì)丟失 Tl 的更新。


DBMS 按照一定的封鎖協(xié)議,對(duì)并發(fā)操作進(jìn)行控制,使得多個(gè)并發(fā)操作有序地執(zhí)行,就可以避免丟失修改、不可重復(fù)讀和讀“臟’夕數(shù)據(jù)等數(shù)據(jù)不一致性。


5 .什么是活鎖?什么是死鎖?
答:
如果事務(wù) Tl 封鎖了數(shù)據(jù) R ,事務(wù)幾又請(qǐng)求封鎖 R ,于是幾等待。幾也請(qǐng)求封鎖 R ,當(dāng) Tl 釋放了 R 上的封鎖之后系統(tǒng)首先批準(zhǔn)了幾的請(qǐng)求,幾仍然等待。然后幾又請(qǐng)求封鎖 R ,當(dāng)幾釋放了 R 上的封鎖之后系統(tǒng)又批準(zhǔn)了幾的請(qǐng)求 … … 幾有可能永遠(yuǎn)等待,這就是活鎖的情形。活鎖的含義是該等待事務(wù)等待時(shí)間太長(zhǎng),似乎被鎖住了,實(shí)際上可能被激活。如果事務(wù) Tl 封鎖了數(shù)據(jù) Rl ,幾封鎖了數(shù)據(jù)凡,然后 Tl 又請(qǐng)求封鎖幾,因幾已封鎖了幾,于是 Tl 等待幾釋放幾上的鎖。接著幾又申請(qǐng)封鎖 Rl ,因 Tl 已封鎖了 Rl ,幾也只能等待 Tl 釋放 Rl 上的鎖。這樣就出現(xiàn)了 Tl 在等待幾,而幾又在等待 T }的局面, T }和幾兩個(gè)事務(wù)永遠(yuǎn)不能結(jié)束,形成死鎖。


6 .試述活鎖的產(chǎn)生原因和解決方法。


答:活鎖產(chǎn)生的原因:當(dāng)一系列封鎖不能按照其先后順序執(zhí)行時(shí),就可能導(dǎo)致一些事務(wù)無(wú)限期等待某個(gè)封鎖,從而導(dǎo)致活鎖。避免活鎖的簡(jiǎn)單方法是采用先來(lái)先服務(wù)的策略。當(dāng)多個(gè)事務(wù)請(qǐng)求封鎖同一數(shù)據(jù)對(duì)象時(shí),封鎖子系統(tǒng)按請(qǐng)求封鎖的先后次序?qū)κ聞?wù)排隊(duì),數(shù)據(jù)對(duì)象上的鎖一旦釋放就批準(zhǔn)申請(qǐng)隊(duì)列中第一個(gè)事務(wù)獲得鎖。


11 .請(qǐng)給出檢測(cè)死鎖發(fā)生的一種方法,當(dāng)發(fā)生死鎖后如何解除死鎖?


答:數(shù)據(jù)庫(kù)系統(tǒng)一般采用允許死鎖發(fā)生, DBMS 檢測(cè)到死鎖后加以解除的方法。 DBMS 中診斷死鎖的方法與操作系統(tǒng)類似,一般使用超時(shí)法或事務(wù)等待圖法。超時(shí)法是:如果一個(gè)事務(wù)的等待時(shí)間超過(guò)了規(guī)定的時(shí)限,就認(rèn)為發(fā)生了死鎖。超時(shí)法實(shí)現(xiàn)簡(jiǎn)單,但有可能誤判死鎖,事務(wù)因其他原因長(zhǎng)時(shí)間等待超過(guò)時(shí)限時(shí),系統(tǒng)會(huì)誤認(rèn)為發(fā)生了死鎖。若時(shí)限設(shè)置得太長(zhǎng),又不能及時(shí)發(fā)現(xiàn)死鎖發(fā)生。 DBMS 并發(fā)控制子系統(tǒng)檢測(cè)到死鎖后,就要設(shè)法解除。通常采用的方法是選擇一個(gè)處理死鎖代價(jià)最小的事務(wù),將其撤消,釋放此事務(wù)持有的所有鎖,使其他事務(wù)得以繼續(xù)運(yùn)行下去。當(dāng)然,對(duì)撤銷的事務(wù)所執(zhí)行的數(shù)據(jù)修改操作必須加以恢復(fù)。


?12 .什么樣的并發(fā)調(diào)度是正確的調(diào)度?


答:可串行化( Serializable )的調(diào)度是正確的調(diào)度。可串行化的調(diào)度的定義:多個(gè)事務(wù)的并發(fā)執(zhí)行是正確的,當(dāng)且僅當(dāng)其結(jié)果與按某一次序串行執(zhí)行它們時(shí)的結(jié)果相同,稱這種調(diào)度策略為可串行化的調(diào)度。


9 .設(shè) Tl ,幾,幾是如下的 3 個(gè)事務(wù):


Tl :A : = A + 2 ;


T2:A : = A * 2 ;


T3:A : = A **2 ; ( A <-A*A)


設(shè) A 的初值為 0 。


( l )若這 3 個(gè)事務(wù)允許并行執(zhí)行,則有多少可能的正確結(jié)果,請(qǐng)一一列舉出來(lái)。


答 :A 的最終結(jié)果可能有 2 、 4 、 8 、 16 。因?yàn)榇袌?zhí)行次序有 Tl T2T3、 Tl T3T2、T2T1T3、T2T3Tl 、T3T1T2、T3T2 Tl 。對(duì)應(yīng)的執(zhí)行結(jié)果是 16 、 8 · 4 · 2 · 4 · 2 。


( 2 )請(qǐng)給出一個(gè)可串行化的調(diào)度,并給出執(zhí)行結(jié)果


答:
最后結(jié)果 A 為 16 ,是可串行化的調(diào)度。


( 3 )請(qǐng)給出一個(gè)非串行化的調(diào)度,并給出執(zhí)行結(jié)果。


答:最后結(jié)果 A 為 0 ,為非串行化的調(diào)度。


( 4 )若這 3 個(gè)事務(wù)都遵守兩段鎖協(xié)議,請(qǐng)給出一個(gè)不產(chǎn)生死鎖的可串行化調(diào)度。


答: ? ??


? ? ?( 5 )若這 3 個(gè)事務(wù)都遵守兩段鎖協(xié)議,請(qǐng)給出一個(gè)產(chǎn)生死鎖的調(diào)度。


答: ? ??


11.試證明,若并發(fā)事務(wù)遵守兩段鎖協(xié)議,則對(duì)這些事務(wù)的并發(fā)調(diào)度是可串行化的。


證明:首先以兩個(gè)并發(fā)事務(wù) Tl 和T2為例,存在多個(gè)并發(fā)事務(wù)的情形可以類推。根據(jù)可串行化定義可知,事務(wù)不可串行化只可能發(fā)生在下列兩種情況:


?( l )事務(wù) Tl 寫某個(gè)數(shù)據(jù)對(duì)象 A ,T2讀或?qū)?A ;


( 2 )事務(wù) Tl 讀或?qū)懩硞€(gè)數(shù)據(jù)對(duì)象 A ,T2寫 A 。


下面稱 A 為潛在沖突對(duì)象。


設(shè) Tl 和T2訪問(wèn)的潛在沖突的公共對(duì)象為{A1,A2 … , An }。不失一般性,假設(shè)這組潛在沖突對(duì)象中 X =(A 1 , A2 , … , Ai }均符合情況 1 。 Y ={A i + 1 , … , An }符合所情況( 2 )。


VX ∈ x , Tl 需要 XlockX ①


T2 需要 Slockx 或 Xlockx ②


?1 )如果操作 ① 先執(zhí)行,則 Tl 獲得鎖,T2等待


由于遵守兩段鎖協(xié)議, Tl 在成功獲得 x 和 Y 中全部對(duì)象及非潛在沖突對(duì)象的鎖后,才會(huì)釋放鎖。


這時(shí)如果存在 w ∈ x 或 Y ,T2已獲得 w 的鎖,則出現(xiàn)死鎖;否則, Tl 在對(duì) x 、 Y 中對(duì)象全部處理完畢后,T2才能執(zhí)行。這相當(dāng)于按 Tl 、T2的順序串行執(zhí)行,根據(jù)可串行化定義, Tl 和幾的調(diào)度是可串行化的。


2 )操作 ② 先執(zhí)行的情況與( l )對(duì)稱因此,若并發(fā)事務(wù)遵守兩段鎖協(xié)議,在不發(fā)生死鎖的情況下,對(duì)這些事務(wù)的并發(fā)調(diào)度一定是可串行化的。證畢。


12 .舉例說(shuō)明,對(duì)并發(fā)事務(wù)的一個(gè)調(diào)度是可串行化的,而這些并發(fā)事務(wù)不一定遵守兩段鎖協(xié)議。


答:


13 .為什么要引進(jìn)意向鎖?意向鎖的含義是什么?


答:引進(jìn)意向鎖是為了提高封鎖子系統(tǒng)的效率。該封鎖子系統(tǒng)支持多種封鎖粒度。原因是:在多粒度封鎖方法中一個(gè)數(shù)據(jù)對(duì)象可能以兩種方式加鎖 ― 顯式封鎖和隱式封鎖。因此系統(tǒng)在對(duì)某一數(shù)據(jù)對(duì)象加鎖時(shí)不僅要檢查該數(shù)據(jù)對(duì)象上有無(wú)(顯式和隱式)封鎖與之沖突,還要檢查其所有上級(jí)結(jié)點(diǎn)和所有下級(jí)結(jié)點(diǎn),看申請(qǐng)的封鎖是否與這些結(jié)點(diǎn)上的(顯式和隱式)封鎖沖突,顯然,這樣的檢查方法效率很低。為此引進(jìn)了意向鎖。意向鎖的含義是:對(duì)任一結(jié)點(diǎn)加鎖時(shí),必須先對(duì)它的上層結(jié)點(diǎn)加意向鎖。例如事務(wù) T 要對(duì)某個(gè)元組加 X 鎖,則首先要對(duì)關(guān)系和數(shù)據(jù)庫(kù)加 ix 鎖。換言之,對(duì)關(guān)系和數(shù)據(jù)庫(kù)加 ix 鎖,表示它的后裔結(jié)點(diǎn) ― 某個(gè)元組擬(意向)加 X 鎖。引進(jìn)意向鎖后,系統(tǒng)對(duì)某一數(shù)據(jù)對(duì)象加鎖時(shí)不必逐個(gè)檢查與下一級(jí)結(jié)點(diǎn)的封鎖沖突了。例如,事務(wù) T 要對(duì)關(guān)系 R 加 X 鎖時(shí),系統(tǒng)只要檢查根結(jié)點(diǎn)數(shù)據(jù)庫(kù)和 R 本身是否已加了不相容的鎖(如發(fā)現(xiàn)已經(jīng)加了 ix ,則與 X 沖突),而不再需要搜索和檢查 R 中的每一個(gè)元組是否加了 X 鎖或 S 鎖。


14 .試述常用的意向鎖: IS 鎖、 ix 鎖、 SIX 鎖,給出這些鎖的相容矩陣。


答: IS鎖:如果對(duì)一個(gè)數(shù)據(jù)對(duì)象加 IS 鎖,表示它的后裔結(jié)點(diǎn)擬(意向)加 S 鎖。例如,要對(duì)某個(gè)元組加 S 鎖,則要首先對(duì)關(guān)系和數(shù)據(jù)庫(kù)加 IS 鎖


IX 鎖:如果對(duì)一個(gè)數(shù)據(jù)對(duì)象加 ix 鎖,表示它的后裔結(jié)點(diǎn)擬(意向功口 X 鎖。例如,要對(duì)某個(gè)元組加 X 鎖,則要首先對(duì)關(guān)系和數(shù)據(jù)庫(kù)加 ix 鎖。


SIX 鎖:如果對(duì)一個(gè)數(shù)據(jù)對(duì)象加 SIX 鎖,表示對(duì)它加 S 鎖,再加 IX 鎖,即 SIX = S + IX 。


相容矩陣:


15 .理解并解釋下列術(shù)語(yǔ)的含義:封鎖、活鎖、死鎖、排它鎖、共享鎖、并發(fā)事務(wù)的調(diào)度、可串行化的調(diào)度、兩段鎖協(xié)議。


答:(略,已經(jīng)在上面有關(guān)習(xí)題中解答)


16 .試述你了解的某一個(gè)實(shí)際的 DBMS 產(chǎn)品的并發(fā)控制機(jī)制。


答:(略,參見(jiàn)簡(jiǎn)單介紹了有關(guān) Oracle 的并發(fā)控制機(jī)制。
========

大數(shù)據(jù)量高并發(fā)的數(shù)據(jù)庫(kù)優(yōu)化

一、數(shù)據(jù)庫(kù)結(jié)構(gòu)的設(shè)計(jì)


? ? 如果不能設(shè)計(jì)一個(gè)合理的數(shù)據(jù)庫(kù)模型,不僅會(huì)增加客戶端和服務(wù)器段程序的編程和維護(hù)的難度,而且將會(huì)影響系統(tǒng)實(shí)際運(yùn)行的性能。所以,在一個(gè)系統(tǒng)開始實(shí)施之前,完備的數(shù)據(jù)庫(kù)模型的設(shè)計(jì)是必須的。
? ? 在一個(gè)系統(tǒng)分析、設(shè)計(jì)階段,因?yàn)閿?shù)據(jù)量較小,負(fù)荷較低。我們往往只注意到功能的實(shí)現(xiàn),而很難注意到性能的薄弱之處,等到系統(tǒng)投入實(shí)際運(yùn)行一段時(shí)間后,才發(fā)現(xiàn)系統(tǒng)的性能在降低,這時(shí)再來(lái)考慮提高系統(tǒng)性能則要花費(fèi)更多的人力物力,而整個(gè)系統(tǒng)也不可避免的形成了一個(gè)打補(bǔ)丁工程。


? ? 所以在考慮整個(gè)系統(tǒng)的流程的時(shí)候,我們必須要考慮,在高并發(fā)大數(shù)據(jù)量的訪問(wèn)情況下,我們的系統(tǒng)會(huì)不會(huì)出現(xiàn)極端的情況。(例如:對(duì)外統(tǒng)計(jì)系統(tǒng)在7月16日出現(xiàn)的數(shù)據(jù)異常的情況,并發(fā)大數(shù)據(jù)量的的訪問(wèn)造成,數(shù)據(jù)庫(kù)的響應(yīng)時(shí)間不能跟上數(shù)據(jù)刷新的速度造成。具體情況是:在日期臨界時(shí)(00:00:00),判斷數(shù)據(jù)庫(kù)中是否有當(dāng)前日期的記錄,沒(méi)有則插入一條當(dāng)前日期的記錄。在低并發(fā)訪問(wèn)的情況下,不會(huì)發(fā)生問(wèn)題,但是當(dāng)日期臨界時(shí)的訪問(wèn)量相當(dāng)大的時(shí)候,在做這一判斷的時(shí)候,會(huì)出現(xiàn)多次條件成立,則數(shù)據(jù)庫(kù)里會(huì)被插入多條當(dāng)前日期的記錄,從而造成數(shù)據(jù)錯(cuò)誤。),數(shù)據(jù)庫(kù)的模型確定下來(lái)之后,我們有必要做一個(gè)系統(tǒng)內(nèi)數(shù)據(jù)流向圖,分析可能出現(xiàn)的瓶頸。


? ? 為了保證數(shù)據(jù)庫(kù)的一致性和完整性,在邏輯設(shè)計(jì)的時(shí)候往往會(huì)設(shè)計(jì)過(guò)多的表間關(guān)聯(lián),盡可能的降低數(shù)據(jù)的冗余。(例如用戶表的地區(qū),我們可以把地區(qū)另外存放到一個(gè)地區(qū)表中)如果數(shù)據(jù)冗余低,數(shù)據(jù)的完整性容易得到保證,提高了數(shù)據(jù)吞吐速度,保證了數(shù)據(jù)的完整性,清楚地表達(dá)數(shù)據(jù)元素之間的關(guān)系。而對(duì)于多表之間的關(guān)聯(lián)查詢(尤其是大數(shù)據(jù)表)時(shí),其性能將會(huì)降低,同時(shí)也提高了客戶端程序的編程難度,因此,物理設(shè)計(jì)需折衷考慮,根據(jù)業(yè)務(wù)規(guī)則,確定對(duì)關(guān)聯(lián)表的數(shù)據(jù)量大小、數(shù)據(jù)項(xiàng)的訪問(wèn)頻度,對(duì)此類數(shù)據(jù)表頻繁的關(guān)聯(lián)查詢應(yīng)適當(dāng)提高數(shù)據(jù)冗余設(shè)計(jì)但增加了表間連接查詢的操作,也使得程序的變得復(fù)雜,為了提高系統(tǒng)的響應(yīng)時(shí)間,合理的數(shù)據(jù)冗余也是必要的。設(shè)計(jì)人員在設(shè)計(jì)階段應(yīng)根據(jù)系統(tǒng)操作的類型、頻度加以均衡考慮。
? ?另外,最好不要用自增屬性字段作為主鍵與子表關(guān)聯(lián)。不便于系統(tǒng)的遷移和數(shù)據(jù)恢復(fù)。對(duì)外統(tǒng)計(jì)系統(tǒng)映射關(guān)系丟失(******************)。


? ? 原來(lái)的表格必須可以通過(guò)由它分離出去的表格重新構(gòu)建。使用這個(gè)規(guī)定的好處是,你可以確保不會(huì)在分離的表格中引入多余的列,所有你創(chuàng)建的表格結(jié)構(gòu)都與它們的實(shí)際需要一樣大。應(yīng)用這條規(guī)定是一個(gè)好習(xí)慣,不過(guò)除非你要處理一個(gè)非常大型的數(shù)據(jù),否則你將不需要用到它。(例如一個(gè)通行證系統(tǒng),我可以將USERID,USERNAME,USERPASSWORD,單獨(dú)出來(lái)作個(gè)表,再把USERID作為其他表的外鍵)


表的設(shè)計(jì)具體注意的問(wèn)題:


? ? 1、數(shù)據(jù)行的長(zhǎng)度不要超過(guò)8020字節(jié),如果超過(guò)這個(gè)長(zhǎng)度的話在物理頁(yè)中這條數(shù)據(jù)會(huì)占用兩行從而造成存儲(chǔ)碎片,降低查詢效率。
? ? 2、能夠用數(shù)字類型的字段盡量選擇數(shù)字類型而不用字符串類型的(電話號(hào)碼),這會(huì)降低查詢和連接的性能,并會(huì)增加存儲(chǔ)開銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接回逐個(gè)比較字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比較一次就夠了。


? ? 3、對(duì)于不可變字符類型char和可變字符類型varchar 都是8000字節(jié),char查詢快,但是耗存儲(chǔ)空間,varchar查詢相對(duì)慢一些但是節(jié)省存儲(chǔ)空間。在設(shè)計(jì)字段的時(shí)候可以靈活選擇,例如用戶名、密碼等長(zhǎng)度變化不大的字段可以選擇CHAR,對(duì)于評(píng)論等長(zhǎng)度變化大的字段可以選擇VARCHAR。


? ? 4、字段的長(zhǎng)度在最大限度的滿足可能的需要的前提下,應(yīng)該盡可能的設(shè)得短一些,這樣可以提高查詢的效率,而且在建立索引的時(shí)候也可以減少資源的消耗。


二、查詢的優(yōu)化?


保證在實(shí)現(xiàn)功能的基礎(chǔ)上,盡量減少對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)次數(shù);通過(guò)搜索參數(shù),盡量減少對(duì)表的訪問(wèn)行數(shù),最小化結(jié)果集,從而減輕網(wǎng)絡(luò)負(fù)擔(dān);能夠分開的操作盡量分開處理,提高每次的響應(yīng)速度;在數(shù)據(jù)窗口使用SQL時(shí),盡量把使用的索引放在選擇的首列;算法的結(jié)構(gòu)盡量簡(jiǎn)單;在查詢時(shí),不要過(guò)多地使用通配符如SELECT * FROM T1語(yǔ)句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下盡量限制盡量結(jié)果集行數(shù)如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因?yàn)槟承┣闆r下用戶是不需要那么多的數(shù)據(jù)的。 ??
在沒(méi)有建索引的情況下,數(shù)據(jù)庫(kù)查找某一條數(shù)據(jù),就必須進(jìn)行全表掃描了,對(duì)所有數(shù)據(jù)進(jìn)行一次遍歷,查找出符合條件的記錄。在數(shù)據(jù)量比較小的情況下,也許看不出明顯的差別,但是當(dāng)數(shù)據(jù)量大的情況下,這種情況就是極為糟糕的了。
SQL語(yǔ)句在SQL SERVER中是如何執(zhí)行的,他們擔(dān)心自己所寫的SQL語(yǔ)句會(huì)被SQL SERVER誤解。比如:?
select * from table1 where name='zhangsan' and tID > 10000?
和執(zhí)行:?
select * from table1 where tID > 10000 and name='zhangsan'?
一些人不知道以上兩條語(yǔ)句的執(zhí)行效率是否一樣,因?yàn)槿绻?jiǎn)單的從語(yǔ)句先后上看,這兩個(gè)語(yǔ)句的確是不一樣,如果tID是一個(gè)聚合索引,那么后一句僅僅從表的10000條以后的記錄中查找就行了;而前一句則要先從全表中查找看有幾個(gè)name='zhangsan'的,而后再根據(jù)限制條件條件tID>10000來(lái)提出查詢結(jié)果。?
事實(shí)上,這樣的擔(dān)心是不必要的。SQL SERVER中有一個(gè)“查詢分析優(yōu)化器”,它可以計(jì)算出where子句中的搜索條件并確定哪個(gè)索引能縮小表掃描的搜索空間,也就是說(shuō),它能實(shí)現(xiàn)自動(dòng)優(yōu)化。雖然查詢優(yōu)化器可以根據(jù)where子句自動(dòng)的進(jìn)行查詢優(yōu)化,但有時(shí)查詢優(yōu)化器就會(huì)不按照您的本意進(jìn)行快速查詢。?
在查詢分析階段,查詢優(yōu)化器查看查詢的每個(gè)階段并決定限制需要掃描的數(shù)據(jù)量是否有用。如果一個(gè)階段可以被用作一個(gè)掃描參數(shù)(SARG),那么就稱之為可優(yōu)化的,并且可以利用索引快速獲得所需數(shù)據(jù)。?
SARG的定義:用于限制搜索的一個(gè)操作,因?yàn)樗ǔJ侵敢粋€(gè)特定的匹配,一個(gè)值的范圍內(nèi)的匹配或者兩個(gè)以上條件的AND連接。形式如下:?
列名 操作符 <常數(shù) 或 變量> 或 <常數(shù) 或 變量> 操作符 列名?
列名可以出現(xiàn)在操作符的一邊,而常數(shù)或變量出現(xiàn)在操作符的另一邊。如:?
Name=’張三’?
價(jià)格>5000?
5000<價(jià)格?
Name=’張三’ and 價(jià)格>5000?
如果一個(gè)表達(dá)式不能滿足SARG的形式,那它就無(wú)法限制搜索的范圍了,也就是SQL SERVER必須對(duì)每一行都判斷它是否滿足WHERE子句中的所有條件。所以一個(gè)索引對(duì)于不滿足SARG形式的表達(dá)式來(lái)說(shuō)是無(wú)用的。?
? ? 所以,優(yōu)化查詢最重要的就是,盡量使語(yǔ)句符合查詢優(yōu)化器的規(guī)則避免全表掃描而使用索引查詢。


具體要注意的:


1.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
select id from t where num is null
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒(méi)有null值,然后這樣查詢:
select id from t where num=0


2.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。優(yōu)化器將無(wú)法通過(guò)索引來(lái)確定將要命中的行數(shù),因此需要搜索該表的所有行。


3.應(yīng)盡量避免在 where 子句中使用 or 來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
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 也要慎用,因?yàn)镮N會(huì)使系統(tǒng)無(wú)法使用索引,而只能直接搜索表中的數(shù)據(jù)。如:
select id from t where num in(1,2,3)
對(duì)于連續(xù)的數(shù)值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3


5.盡量避免在索引過(guò)的字符數(shù)據(jù)中,使用非打頭字母搜索。這也使得引擎無(wú)法利用索引。?
見(jiàn)如下例子:?
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’?
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’?
SELECT * FROM T1 WHERE NAME LIKE ‘L%’?
即使NAME字段建有索引,前兩個(gè)查詢依然無(wú)法利用索引完成加快操作,引擎不得不對(duì)全表所有數(shù)據(jù)逐條操作來(lái)完成任務(wù)。而第三個(gè)查詢能夠使用索引來(lái)加快操作。


6.必要時(shí)強(qiáng)制查詢優(yōu)化器使用某個(gè)索引,如在 where 子句中使用參數(shù),也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問(wèn)計(jì)劃的選擇推遲到運(yùn)行時(shí);它必須在編譯時(shí)進(jìn)行選擇。然而,如果在編譯時(shí)建立訪問(wèn)計(jì)劃,變量的值還是未知的,因而無(wú)法作為索引選擇的輸入項(xiàng)。如下面語(yǔ)句將進(jìn)行全表掃描:
select id from t where num=@num
可以改為強(qiáng)制查詢使用索引:
select id from t with(index(索引名)) where num=@num


7.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
SELECT * FROM T1 WHERE F1/2=100?
應(yīng)改為:?
SELECT * FROM T1 WHERE F1=100*2


SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’?
應(yīng)改為:?
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’


SELECT member_number, first_name, last_name FROM members?
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21?
應(yīng)改為:?
SELECT member_number, first_name, last_name FROM members?
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())?
即:任何對(duì)列的操作都將導(dǎo)致表掃描,它包括數(shù)據(jù)庫(kù)函數(shù)、計(jì)算表達(dá)式等等,查詢時(shí)要盡可能將操作移至等號(hào)右邊。


8.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
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
應(yīng)改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'


9.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無(wú)法正確使用索引。


10.在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。


11.很多時(shí)候用 exists是一個(gè)好的選擇:
elect num from a where num in(select num from b)
用下面的語(yǔ)句替換:
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)?
兩者產(chǎn)生相同的結(jié)果,但是后者的效率顯然要高于前者。因?yàn)楹笳卟粫?huì)產(chǎn)生大量鎖定的表掃描或是索引掃描。


如果你想校驗(yàn)表里是否存在某條紀(jì)錄,不要用count(*)那樣效率很低,而且浪費(fèi)服務(wù)器資源。可以用EXISTS代替。如:?
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')?
可以寫成:?
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')


經(jīng)常需要寫一個(gè)T_SQL語(yǔ)句比較一個(gè)父結(jié)果集和子結(jié)果集,從而找到是否存在在父結(jié)果集中有而在子結(jié)果集中沒(méi)有的記錄,如:?
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)?
三種寫法都可以得到同樣正確的結(jié)果,但是效率依次降低。


12.盡量使用表變量來(lái)代替臨時(shí)表。如果表變量包含大量數(shù)據(jù),請(qǐng)注意索引非常有限(只有主鍵索引)。


13.避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。


14.臨時(shí)表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行?#xff0c;例如,當(dāng)需要重復(fù)引用大型表或常用表中的某個(gè)數(shù)據(jù)集時(shí)。但是,對(duì)于一次性事件,最好使用導(dǎo)出表。


15.在新建臨時(shí)表時(shí),如果一次性插入數(shù)據(jù)量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create table,然后insert。


16.如果使用到了臨時(shí)表,在存儲(chǔ)過(guò)程的最后務(wù)必將所有的臨時(shí)表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統(tǒng)表的較長(zhǎng)時(shí)間鎖定。?


17.在所有的存儲(chǔ)過(guò)程和觸發(fā)器的開始處設(shè)置 SET NOCOUNT ON ,在結(jié)束時(shí)設(shè)置 SET NOCOUNT OFF 。無(wú)需在執(zhí)行存儲(chǔ)過(guò)程和觸發(fā)器的每個(gè)語(yǔ)句后向客戶端發(fā)送 DONE_IN_PROC 消息。


18.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。


19.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過(guò)大,應(yīng)該考慮相應(yīng)需求是否合理。?


20. 避免使用不兼容的數(shù)據(jù)類型。例如float和int、char和varchar、binary和varbinary是不兼容的。數(shù)據(jù)類型的不兼容可能使優(yōu)化器無(wú)法執(zhí)行一些本來(lái)可以進(jìn)行的優(yōu)化操作。例如:?
SELECT name FROM employee WHERE salary > 60000?
在這條語(yǔ)句中,如salary字段是money型的,則優(yōu)化器很難對(duì)其進(jìn)行優(yōu)化,因?yàn)?0000是個(gè)整型數(shù)。我們應(yīng)當(dāng)在編程時(shí)將整型轉(zhuǎn)化成為錢幣型,而不要等到運(yùn)行時(shí)轉(zhuǎn)化。


21.充分利用連接條件,在某種情況下,兩個(gè)表之間可能不只一個(gè)的連接條件,這時(shí)在 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?
第二句將比第一句執(zhí)行快得多。


22、使用視圖加速查詢?
把表的一個(gè)子集進(jìn)行排序并創(chuàng)建視圖,有時(shí)能加速查詢。它有助于避免多重排序 操作,而且在其他方面還能簡(jiǎn)化優(yōu)化器的工作。例如:
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


如果這個(gè)查詢要被執(zhí)行多次而不止一次,可以把所有未付款的客戶找出來(lái)放在一個(gè)視圖中,并按客戶的名字進(jìn)行排序:?
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不執(zhí)行SELECT DISTINCT函數(shù),這樣就會(huì)減少很多不必要的資源?


35.盡量不要用SELECT INTO語(yǔ)句。?
SELECT INOT 語(yǔ)句會(huì)導(dǎo)致表鎖定,阻止其他用戶訪問(wèn)該表。


? ? 上面我們提到的是一些基本的提高查詢速度的注意事項(xiàng),但是在更多的情況下,往往需要反復(fù)試驗(yàn)比較不同的語(yǔ)句以得到最佳方案。最好的方法當(dāng)然是測(cè)試,看實(shí)現(xiàn)相同功能的SQL語(yǔ)句哪個(gè)執(zhí)行時(shí)間最少,但是數(shù)據(jù)庫(kù)中如果數(shù)據(jù)量很少,是比較不出來(lái)的,這時(shí)可以用查看執(zhí)行計(jì)劃,即:把實(shí)現(xiàn)相同功能的多條SQL語(yǔ)句考到查詢分析器,按CTRL+L看查所利用的索引,表掃描次數(shù)(這兩個(gè)對(duì)性能影響最大),總體上看詢成本百分比即可。?


三、算法的優(yōu)化


盡量避免使用游標(biāo),因?yàn)橛螛?biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過(guò)1萬(wàn)行,那么就應(yīng)該考慮改寫。.使用基于游標(biāo)的方法或臨時(shí)表方法之前,應(yīng)先尋找基于集的解決方案來(lái)解決問(wèn)題,基于集的方法通常更有效。與臨時(shí)表一樣,游標(biāo)并不是不可使用。對(duì)小型數(shù)據(jù)集使用 FAST_FORWARD 游標(biāo)通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個(gè)表才能獲得所需的數(shù)據(jù)時(shí)。在結(jié)果集中包括“合計(jì)”的例程通常要比使用游標(biāo)執(zhí)行的速度快。如果開發(fā)時(shí)間允許,基于游標(biāo)的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
  游標(biāo)提供了對(duì)特定集合中逐行掃描的手段,一般使用游標(biāo)逐行遍歷數(shù)據(jù),根據(jù)取出的數(shù)據(jù)不同條件進(jìn)行不同的操作。尤其對(duì)多表和大表定義的游標(biāo)(大的數(shù)據(jù)集合)循環(huán)很容易使程序進(jìn)入一個(gè)漫長(zhǎng)的等特甚至死機(jī)。?
  在有些場(chǎng)合,有時(shí)也非得使用游標(biāo),此時(shí)也可考慮將符合條件的數(shù)據(jù)行轉(zhuǎn)入臨時(shí)表中,再對(duì)臨時(shí)表定義游標(biāo)進(jìn)行操作,可時(shí)性能得到明顯提高。
(例如:對(duì)內(nèi)統(tǒng)計(jì)第一版)
封裝存儲(chǔ)過(guò)程


四、建立高效的索引


  創(chuàng)建索引一般有以下兩個(gè)目的:維護(hù)被索引列的唯一性和提供快速訪問(wèn)表中數(shù)據(jù)的策略。大型數(shù)據(jù)庫(kù)有兩種索引即簇索引和非簇索引,一個(gè)沒(méi)有簇索引的表是按堆結(jié)構(gòu)存儲(chǔ)數(shù)據(jù),所有的數(shù)據(jù)均添加在表的尾部,而建立了簇索引的表,其數(shù)據(jù)在物理上會(huì)按照簇索引鍵的順序存儲(chǔ),一個(gè)表只允許有一個(gè)簇索引,因此,根據(jù)B樹結(jié)構(gòu),可以理解添加任何一種索引均能提高按索引列查詢的速度,但會(huì)降低插入、更新、刪除操作的性能,尤其是當(dāng)填充因子(Fill Factor)較大時(shí)。所以對(duì)索引較多的表進(jìn)行頻繁的插入、更新、刪除操作,建表和索引時(shí)因設(shè)置較小的填充因子,以便在各數(shù)據(jù)頁(yè)中留下較多的自由空間,減少頁(yè)分割及重新組織的工作。?
索引是從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)的最高效方式之一。95% 的數(shù)據(jù)庫(kù)性能問(wèn)題都可以采用索引技術(shù)得到解決。作為一條規(guī)則,我通常對(duì)邏輯主鍵使用唯一的成組索引,對(duì)系統(tǒng)鍵(作為存儲(chǔ)過(guò)程)采用唯一的非成組索引,對(duì)任何外鍵列[字段]采用非成組索引。不過(guò),索引就象是鹽,太多了菜就咸了。你得考慮數(shù)據(jù)庫(kù)的空間有多大,表如何進(jìn)行訪問(wèn),還有這些訪問(wèn)是否主要用作讀寫。?
實(shí)際上,您可以把索引理解為一種特殊的目錄。微軟的SQL SERVER提供了兩種索引:聚集索引(clustered index,也稱聚類索引、簇集索引)和非聚集索引(nonclustered index,也稱非聚類索引、非簇集索引)。下面,我們舉例來(lái)說(shuō)明一下聚集索引和非聚集索引的區(qū)別:?
其實(shí),我們的漢語(yǔ)字典的正文本身就是一個(gè)聚集索引。比如,我們要查“安”字,就會(huì)很自然地翻開字典的前幾頁(yè),因?yàn)椤鞍病钡钠匆羰恰癮n”,而按照拼音排序漢字的字典是以英文字母“a”開頭并以“z”結(jié)尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”開頭的部分仍然找不到這個(gè)字,那么就說(shuō)明您的字典中沒(méi)有這個(gè)字;同樣的,如果查“張”字,那您也會(huì)將您的字典翻到最后部分,因?yàn)椤皬垺钡钠匆羰恰皕hang”。也就是說(shuō),字典的正文部分本身就是一個(gè)目錄,您不需要再去查其他目錄來(lái)找到您需要找的內(nèi)容。?
我們把這種正文內(nèi)容本身就是一種按照一定規(guī)則排列的目錄稱為“聚集索引”。?
如果您認(rèn)識(shí)某個(gè)字,您可以快速地從自動(dòng)中查到這個(gè)字。但您也可能會(huì)遇到您不認(rèn)識(shí)的字,不知道它的發(fā)音,這時(shí)候,您就不能按照剛才的方法找到您要查的字,而需要去根據(jù)“偏旁部首”查到您要找的字,然后根據(jù)這個(gè)字后的頁(yè)碼直接翻到某頁(yè)來(lái)找到您要找的字。但您結(jié)合“部首目錄”和“檢字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“張”字,我們可以看到在查部首之后的檢字表中“張”的頁(yè)碼是672頁(yè),檢字表中“張”的上面是“馳”字,但頁(yè)碼卻是63頁(yè),“張”的下面是“弩”字,頁(yè)面是390頁(yè)。很顯然,這些字并不是真正的分別位于“張”字的上下方,現(xiàn)在您看到的連續(xù)的“馳、張、弩”三字實(shí)際上就是他們?cè)诜蔷奂饕械呐判?#xff0c;是字典正文中的字在非聚集索引中的映射。我們可以通過(guò)這種方式來(lái)找到您所需要的字,但它需要兩個(gè)過(guò)程,先找到目錄中的結(jié)果,然后再翻到您所需要的頁(yè)碼。?
我們把這種目錄純粹是目錄,正文純粹是正文的排序方式稱為“非聚集索引”。?
進(jìn)一步引申一下,我們可以很容易的理解:每個(gè)表只能有一個(gè)聚集索引,因?yàn)槟夸浿荒馨凑找环N方法進(jìn)行排序。


(一)何時(shí)使用聚集索引或非聚集索引?
下面的表總結(jié)了何時(shí)使用聚集索引或非聚集索引(很重要)。?
動(dòng)作描述 使用聚集索引 使用非聚集索引?
列經(jīng)常被分組排序 應(yīng) 應(yīng)?
返回某范圍內(nèi)的數(shù)據(jù) 應(yīng) 不應(yīng)?
一個(gè)或極少不同值 不應(yīng) 不應(yīng)?
小數(shù)目的不同值 應(yīng) 不應(yīng)?
大數(shù)目的不同值 不應(yīng) 應(yīng)?
頻繁更新的列 不應(yīng) 應(yīng)?
外鍵列 應(yīng) 應(yīng)?
主鍵列 應(yīng) 應(yīng)?
頻繁修改索引列 不應(yīng) 應(yīng)


事實(shí)上,我們可以通過(guò)前面聚集索引和非聚集索引的定義的例子來(lái)理解上表。如:返回某范圍內(nèi)的數(shù)據(jù)一項(xiàng)。比如您的某個(gè)表有一個(gè)時(shí)間列,恰好您把聚合索引建立在了該列,這時(shí)您查詢2004年1月1日至2004年10月1日之間的全部數(shù)據(jù)時(shí),這個(gè)速度就將是很快的,因?yàn)槟倪@本字典正文是按日期進(jìn)行排序的,聚類索引只需要找到要檢索的所有數(shù)據(jù)中的開頭和結(jié)尾數(shù)據(jù)即可;而不像非聚集索引,必須先查到目錄中查到每一項(xiàng)數(shù)據(jù)對(duì)應(yīng)的頁(yè)碼,然后再根據(jù)頁(yè)碼查到具體內(nèi)容。


(二)結(jié)合實(shí)際,談索引使用的誤區(qū)


理論的目的是應(yīng)用。雖然我們剛才列出了何時(shí)應(yīng)使用聚集索引或非聚集索引,但在實(shí)踐中以上規(guī)則卻很容易被忽視或不能根據(jù)實(shí)際情況進(jìn)行綜合分析。下面我們將根據(jù)在實(shí)踐中遇到的實(shí)際問(wèn)題來(lái)談一下索引使用的誤區(qū),以便于大家掌握索引建立的方法。?
1、主鍵就是聚集索引?
這種想法筆者認(rèn)為是極端錯(cuò)誤的,是對(duì)聚集索引的一種浪費(fèi)。雖然SQL SERVER默認(rèn)是在主鍵上建立聚集索引的。?
通常,我們會(huì)在每個(gè)表中都建立一個(gè)ID列,以區(qū)分每條數(shù)據(jù),并且這個(gè)ID列是自動(dòng)增大的,步長(zhǎng)一般為1。我們的這個(gè)辦公自動(dòng)化的實(shí)例中的列Gid就是如此。此時(shí),如果我們將這個(gè)列設(shè)為主鍵,SQL SERVER會(huì)將此列默認(rèn)為聚集索引。這樣做有好處,就是可以讓您的數(shù)據(jù)在數(shù)據(jù)庫(kù)中按照ID進(jìn)行物理排序,但筆者認(rèn)為這樣做意義不大。?
顯而易見(jiàn),聚集索引的優(yōu)勢(shì)是很明顯的,而每個(gè)表中只能有一個(gè)聚集索引的規(guī)則,這使得聚集索引變得更加珍貴。?
從我們前面談到的聚集索引的定義我們可以看出,使用聚集索引的最大好處就是能夠根據(jù)查詢要求,迅速縮小查詢范圍,避免全表掃描。在實(shí)際應(yīng)用中,因?yàn)镮D號(hào)是自動(dòng)生成的,我們并不知道每條記錄的ID號(hào),所以我們很難在實(shí)踐中用ID號(hào)來(lái)進(jìn)行查詢。這就使讓ID號(hào)這個(gè)主鍵作為聚集索引成為一種資源浪費(fèi)。其次,讓每個(gè)ID號(hào)都不同的字段作為聚集索引也不符合“大數(shù)目的不同值情況下不應(yīng)建立聚合索引”規(guī)則;當(dāng)然,這種情況只是針對(duì)用戶經(jīng)常修改記錄內(nèi)容,特別是索引項(xiàng)的時(shí)候會(huì)負(fù)作用,但對(duì)于查詢速度并沒(méi)有影響。?
在辦公自動(dòng)化系統(tǒng)中,無(wú)論是系統(tǒng)首頁(yè)顯示的需要用戶簽收的文件、會(huì)議還是用戶進(jìn)行文件查詢等任何情況下進(jìn)行數(shù)據(jù)查詢都離不開字段的是“日期”還有用戶本身的“用戶名”。?
通常,辦公自動(dòng)化的首頁(yè)會(huì)顯示每個(gè)用戶尚未簽收的文件或會(huì)議。雖然我們的where語(yǔ)句可以僅僅限制當(dāng)前用戶尚未簽收的情況,但如果您的系統(tǒng)已建立了很長(zhǎng)時(shí)間,并且數(shù)據(jù)量很大,那么,每次每個(gè)用戶打開首頁(yè)的時(shí)候都進(jìn)行一次全表掃描,這樣做意義是不大的,絕大多數(shù)的用戶1個(gè)月前的文件都已經(jīng)瀏覽過(guò)了,這樣做只能徒增數(shù)據(jù)庫(kù)的開銷而已。事實(shí)上,我們完全可以讓用戶打開系統(tǒng)首頁(yè)時(shí),數(shù)據(jù)庫(kù)僅僅查詢這個(gè)用戶近3個(gè)月來(lái)未閱覽的文件,通過(guò)“日期”這個(gè)字段來(lái)限制表掃描,提高查詢速度。如果您的辦公自動(dòng)化系統(tǒng)已經(jīng)建立的2年,那么您的首頁(yè)顯示速度理論上將是原來(lái)速度8倍,甚至更快。


2、只要建立索引就能顯著提高查詢速度?
事實(shí)上,我們可以發(fā)現(xiàn)上面的例子中,第2、3條語(yǔ)句完全相同,且建立索引的字段也相同;不同的僅是前者在fariqi字段上建立的是非聚合索引,后者在此字段上建立的是聚合索引,但查詢速度卻有著天壤之別。所以,并非是在任何字段上簡(jiǎn)單地建立索引就能提高查詢速度。
從建表的語(yǔ)句中,我們可以看到這個(gè)有著1000萬(wàn)數(shù)據(jù)的表中fariqi字段有5003個(gè)不同記錄。在此字段上建立聚合索引是再合適不過(guò)了。在現(xiàn)實(shí)中,我們每天都會(huì)發(fā)幾個(gè)文件,這幾個(gè)文件的發(fā)文日期就相同,這完全符合建立聚集索引要求的:“既不能絕大多數(shù)都相同,又不能只有極少數(shù)相同”的規(guī)則。由此看來(lái),我們建立“適當(dāng)”的聚合索引對(duì)于我們提高查詢速度是非常重要的。


3、把所有需要提高查詢速度的字段都加進(jìn)聚集索引,以提高查詢速度?
上面已經(jīng)談到:在進(jìn)行數(shù)據(jù)查詢時(shí)都離不開字段的是“日期”還有用戶本身的“用戶名”。既然這兩個(gè)字段都是如此的重要,我們可以把他們合并起來(lái),建立一個(gè)復(fù)合索引(compound index)。?
很多人認(rèn)為只要把任何字段加進(jìn)聚集索引,就能提高查詢速度,也有人感到迷惑:如果把復(fù)合的聚集索引字段分開查詢,那么查詢速度會(huì)減慢嗎?帶著這個(gè)問(wèn)題,我們來(lái)看一下以下的查詢速度(結(jié)果集都是25萬(wàn)條數(shù)據(jù)):(日期列fariqi首先排在復(fù)合聚集索引的起始列,用戶名neibuyonghu排在后列)?
我們可以看到如果僅用聚集索引的起始列作為查詢條件和同時(shí)用到復(fù)合聚集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的復(fù)合索引列還要略快(在查詢結(jié)果集數(shù)目一樣的情況下);而如果僅用復(fù)合聚集索引的非起始列作為查詢條件的話,這個(gè)索引是不起任何作用的。當(dāng)然,語(yǔ)句1、2的查詢速度一樣是因?yàn)椴樵兊臈l目數(shù)一樣,如果復(fù)合索引的所有列都用上,而且查詢結(jié)果少的話,這樣就會(huì)形成“索引覆蓋”,因而性能可以達(dá)到最優(yōu)。同時(shí),請(qǐng)記住:無(wú)論您是否經(jīng)常使用聚合索引的其他列,但其前導(dǎo)列一定要是使用最頻繁的列。


(三)其他注意事項(xiàng)?
“水可載舟,亦可覆舟”,索引也一樣。索引有助于提高檢索性能,但過(guò)多或不當(dāng)?shù)乃饕矔?huì)導(dǎo)致系統(tǒng)低效。因?yàn)橛脩粼诒碇忻考舆M(jìn)一個(gè)索引,數(shù)據(jù)庫(kù)就要做更多的工作。過(guò)多的索引甚至?xí)?dǎo)致索引碎片。?
所以說(shuō),我們要建立一個(gè)“適當(dāng)”的索引體系,特別是對(duì)聚合索引的創(chuàng)建,更應(yīng)精益求精,以使您的數(shù)據(jù)庫(kù)能得到高性能的發(fā)揮
?
好像沒(méi)有提到高并發(fā)的解決方案


索引的使用,學(xué)習(xí)了
?
高并發(fā)都用NoSQL了,內(nèi)存數(shù)據(jù)庫(kù)是解決高并發(fā)實(shí)時(shí)性能的方向,
這里有國(guó)人開源的高并發(fā)框架 www. 8088net .com
========

怎么解決數(shù)據(jù)庫(kù)并發(fā)的問(wèn)題



1.用一個(gè)標(biāo)識(shí),在選擇那張票的時(shí)候先用
(Update ?表 ?set ?票flag=‘占用了!’ ?where ?票flag=‘未占用’ ?and ?........)
這樣是保險(xiǎn)的,不可能存在并發(fā)問(wèn)題,這就牽扯到sql鎖機(jī)制問(wèn)題了,你可以測(cè)試一下,其實(shí)sql中update是先查詢出然后刪除再添加,但由于使用了update,過(guò)程中就自動(dòng)加鎖了,很方便吧
2.加鎖。
Microsoft&reg; ?SQL ?Server&#8482; ?2000 ?使用鎖定確保事務(wù)完整性和數(shù)據(jù)庫(kù)一致性。鎖定可以防止用戶讀取正在由其他用戶更改的數(shù)據(jù),并可以防止多個(gè)用戶同時(shí)更改相同數(shù)據(jù)。如果不使用鎖定,則數(shù)據(jù)庫(kù)中的數(shù)據(jù)可能在邏輯上不正確,并且對(duì)數(shù)據(jù)的查詢可能會(huì)產(chǎn)生意想不到的結(jié)果。
雖然 ?SQL ?Server ?自動(dòng)強(qiáng)制鎖定,但可以通過(guò)了解鎖定并在應(yīng)用程序中自定義鎖定來(lái)設(shè)計(jì)更有效的應(yīng)用程序。
========

關(guān)于數(shù)據(jù)庫(kù)的并發(fā)性的一個(gè)解決方案



我先把流程說(shuō)出來(lái),,比如修改一個(gè)記錄:
當(dāng)用戶點(diǎn)修改時(shí),從數(shù)據(jù)庫(kù)讀出數(shù)據(jù)并顯示到編輯菜單中,然后再編輯數(shù)據(jù),再點(diǎn)確定保存到數(shù)據(jù)庫(kù)中。如果多個(gè)用戶,當(dāng)A用戶點(diǎn)修改到保存該數(shù)據(jù)這一時(shí)間段,,B用戶不能修改,,這個(gè)好像不能用事務(wù)來(lái)做吧,,,大家給個(gè)解決方案,,但是我覺(jué)得還有點(diǎn)矛盾。當(dāng)這一時(shí)間段用戶能修改,那么對(duì)于A用戶來(lái)說(shuō)數(shù)據(jù)就已經(jīng)不一致了,A用戶看到的是B用戶沒(méi)有修改前的數(shù)據(jù),如果不能修改,也不現(xiàn)實(shí),,如果B用戶點(diǎn)了修改還沒(méi)點(diǎn)確定,,然后用戶出去辦急事或WC,,那A用戶不是一直等,,,
網(wǎng)上經(jīng)常舉賣車票的例子,當(dāng)售票員A聽到買票人后開始查詢,發(fā)現(xiàn)有2張,,買票人正好要2張,,在查詢和售出這一時(shí)間段,如果其它窗口不能賣,,好像不太現(xiàn)實(shí),,有時(shí)這一時(shí)間段還是很長(zhǎng)的,,一分鐘左右吧,,其它10多個(gè)窗口窗口不能賣這一車次的不是很要命,并且每個(gè)窗口都會(huì)差不多占一車次的查詢,,如果在查詢到確定出售這一價(jià)段其它窗口可以賣,,也出現(xiàn)問(wèn)題了,,售票員A查詢發(fā)現(xiàn)剩兩張,,告訴買票的人,正好剩兩張,,這時(shí)客戶確定要,如果在這一時(shí)間段,其它窗口賣一張,,那在確定賣出去時(shí)將會(huì)失敗,難道要跟買票人解釋。,,這問(wèn)題其它也困我很久了,,謝謝大家給我一個(gè)解決方案,,也許是我想錯(cuò)了,,在線等


SQL的鎖機(jī)制
一. 為什么要引入鎖
多個(gè)用戶同時(shí)對(duì)數(shù)據(jù)庫(kù)的并發(fā)操作時(shí)會(huì)帶來(lái)以下數(shù)據(jù)不一致的問(wèn)題:
丟失更新
A,B兩個(gè)用戶讀同一數(shù)據(jù)并進(jìn)行修改,其中一個(gè)用戶的修改結(jié)果破壞了另一個(gè)修改的結(jié)果,比如訂票系統(tǒng)
臟讀
A用戶修改了數(shù)據(jù),隨后B用戶又讀出該數(shù)據(jù),但A用戶因?yàn)槟承┰蛉∠藢?duì)數(shù)據(jù)的修改,數(shù)據(jù)恢復(fù)原值,此時(shí)B得到的數(shù)據(jù)就與數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù)產(chǎn)生了不一致
不可重復(fù)讀
A用戶讀取數(shù)據(jù),隨后B用戶讀出該數(shù)據(jù)并修改,此時(shí)A用戶再讀取數(shù)據(jù)時(shí)發(fā)現(xiàn)前后兩次的值不一致
并發(fā)控制的主要方法是封鎖,鎖就是在一段時(shí)間內(nèi)禁止用戶做某些操作以避免產(chǎn)生數(shù)據(jù)不一致
二 ?鎖的分類
鎖的類別有兩種分法:
1. ?從數(shù)據(jù)庫(kù)系統(tǒng)的角度來(lái)看:分為獨(dú)占鎖(即排它鎖),共享鎖和更新鎖
MS-SQL Server 使用以下資源鎖模式。
鎖模式 ? ? ?描述?
共享 ? ? ? ?(S) 用于不更改或不更新數(shù)據(jù)的操作(只讀操作),如 SELECT 語(yǔ)句。?
更新 (U) ? ? 用于可更新的資源中。防止當(dāng)多個(gè)會(huì)話在讀取、鎖定以及隨后可能進(jìn)行的資源更新時(shí)發(fā)生常見(jiàn)形式的死鎖。?
排它 (X) ? ? 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會(huì)同時(shí)同一資源進(jìn)行多重更新。?
意向鎖 ? ? ? 用于建立鎖的層次結(jié)構(gòu)。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。?
架構(gòu)鎖 ? ? ? ?在執(zhí)行依賴于表架構(gòu)的操作時(shí)使用。架構(gòu)鎖的類型為:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。?
大容量更新 (BU) 向表中大容量復(fù)制數(shù)據(jù)并指定了 TABLOCK 提示時(shí)使用。?


共享鎖
共享 (S) 鎖允許并發(fā)事務(wù)讀取 (SELECT) 一個(gè)資源。資源上存在共享 (S) 鎖時(shí),任何其它事務(wù)都不能修改數(shù)據(jù)。一旦已經(jīng)讀取數(shù)據(jù),便立即釋放資源上的共享 (S) 鎖,除非將事務(wù)隔離級(jí)別設(shè)置為可重復(fù)讀或更高級(jí)別,或者在事務(wù)生存周期內(nèi)用鎖定提示保留共享 (S) 鎖。
更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個(gè)事務(wù)組成,此事務(wù)讀取記錄,獲取資源(頁(yè)或行)的共享 (S) 鎖,然后修改行,此操作要求鎖轉(zhuǎn)換為排它 (X) 鎖。如果兩個(gè)事務(wù)獲得了資源上的共享模式鎖,然后試圖同時(shí)更新數(shù)據(jù),則一個(gè)事務(wù)嘗試將鎖轉(zhuǎn)換為排它 (X) 鎖。共享模式到排它鎖的轉(zhuǎn)換必須等待一段時(shí)間,因?yàn)橐粋€(gè)事務(wù)的排它鎖與其它事務(wù)的共享模式鎖不兼容;發(fā)生鎖等待。第二個(gè)事務(wù)試圖獲取排它 (X) 鎖以進(jìn)行更新。由于兩個(gè)事務(wù)都要轉(zhuǎn)換為排它 (X) 鎖,并且每個(gè)事務(wù)都等待另一個(gè)事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。


若要避免這種潛在的死鎖問(wèn)題,請(qǐng)使用更新 (U) 鎖。一次只有一個(gè)事務(wù)可以獲得資源的更新 (U) 鎖。如果事務(wù)修改資源,則更新 (U) 鎖轉(zhuǎn)換為排它 (X) 鎖。否則,鎖轉(zhuǎn)換為共享鎖。


排它鎖
排它 (X) 鎖可以防止并發(fā)事務(wù)對(duì)資源進(jìn)行訪問(wèn)。其它事務(wù)不能讀取或修改排它 (X) 鎖鎖定的數(shù)據(jù)。


意向鎖
意向鎖表示 SQL Server 需要在層次結(jié)構(gòu)中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級(jí)的共享意向鎖表示事務(wù)打算在表中的頁(yè)或行上放置共享 (S) 鎖。在表級(jí)設(shè)置意向鎖可防止另一個(gè)事務(wù)隨后在包含那一頁(yè)的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因?yàn)?SQL Server 僅在表級(jí)檢查意向鎖來(lái)確定事務(wù)是否可以安全地獲取該表上的鎖。而無(wú)須檢查表中的每行或每頁(yè)上的鎖以確定事務(wù)是否可以鎖定整個(gè)表。


意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。


鎖模式 描述?
意向共享 (IS) 通過(guò)在各資源上放置 S 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的部分(而不是全部)底層資源。?
意向排它 (IX) 通過(guò)在各資源上放置 X 鎖,表明事務(wù)的意向是修改層次結(jié)構(gòu)中的部分(而不是全部)底層資源。IX 是 IS 的超集。?
與意向排它共享 (SIX) 通過(guò)在各資源上放置 IX 鎖,表明事務(wù)的意向是讀取層次結(jié)構(gòu)中的全部底層資源并修改部分(而不是全部)底層資源。允許頂層資源上的并發(fā) IS 鎖。例如,表的 SIX 鎖在表上放置一個(gè) SIX 鎖(允許并發(fā) IS 鎖),在當(dāng)前所修改頁(yè)上放置 IX 鎖(在已修改行上放置 X 鎖)。雖然每個(gè)資源在一段時(shí)間內(nèi)只能有一個(gè) SIX 鎖,以防止其它事務(wù)對(duì)資源進(jìn)行更新,但是其它事務(wù)可以通過(guò)獲取表級(jí)的 IS 鎖來(lái)讀取層次結(jié)構(gòu)中的底層資源。?


獨(dú)占鎖:只允許進(jìn)行鎖定操作的程序使用,其他任何對(duì)他的操作均不會(huì)被接受。執(zhí)行數(shù)據(jù)更新命令時(shí),SQL Server會(huì)自動(dòng)使用獨(dú)占鎖。當(dāng)對(duì)象上有其他鎖存在時(shí),無(wú)法對(duì)其加獨(dú)占鎖。
共享鎖:共享鎖鎖定的資源可以被其他用戶讀取,但其他用戶無(wú)法修改它,在執(zhí)行Select時(shí),SQL Server會(huì)對(duì)對(duì)象加共享鎖。
更新鎖:當(dāng)SQL Server準(zhǔn)備更新數(shù)據(jù)時(shí),它首先對(duì)數(shù)據(jù)對(duì)象作更新鎖鎖定,這樣數(shù)據(jù)將不能被修改,但可以讀取。等到SQL Server確定要進(jìn)行更新數(shù)據(jù)操作時(shí),他會(huì)自動(dòng)將更新鎖換為獨(dú)占鎖,當(dāng)對(duì)象上有其他鎖存在時(shí),無(wú)法對(duì)其加更新鎖。
2. 從程序員的角度看:分為樂(lè)觀鎖和悲觀鎖。
樂(lè)觀鎖:完全依靠數(shù)據(jù)庫(kù)來(lái)管理鎖的工作。
悲觀鎖:程序員自己管理數(shù)據(jù)或?qū)ο笊系逆i處理。


MS-SQLSERVER 使用鎖在多個(gè)同時(shí)在數(shù)據(jù)庫(kù)內(nèi)執(zhí)行修改的用戶間實(shí)現(xiàn)悲觀并發(fā)控制


三 ?鎖的粒度
? ?鎖粒度是被封鎖目標(biāo)的大小,封鎖粒度小則并發(fā)性高,但開銷大,封鎖粒度大則并發(fā)性低但開銷小


SQL Server支持的鎖粒度可以分為為行、頁(yè)、鍵、鍵范圍、索引、表或數(shù)據(jù)庫(kù)獲取鎖


資源 ? ? ? ? 描述?
RID ? ? ? ? 行標(biāo)識(shí)符。用于單獨(dú)鎖定表中的一行。?
鍵 ? ? ? ? ? 索引中的行鎖。用于保護(hù)可串行事務(wù)中的鍵范圍。?
頁(yè) ? ? ? ? ? 8 千字節(jié) (KB) 的數(shù)據(jù)頁(yè)或索引頁(yè)。?
擴(kuò)展盤區(qū) ? ? 相鄰的八個(gè)數(shù)據(jù)頁(yè)或索引頁(yè)構(gòu)成的一組。?
表 ? ? ? ? ? 包括所有數(shù)據(jù)和索引在內(nèi)的整個(gè)表。?
DB ? ? ? ? ?數(shù)據(jù)庫(kù)。?


四 ?鎖定時(shí)間的長(zhǎng)短


鎖保持的時(shí)間長(zhǎng)度為保護(hù)所請(qǐng)求級(jí)別上的資源所需的時(shí)間長(zhǎng)度。?


用于保護(hù)讀取操作的共享鎖的保持時(shí)間取決于事務(wù)隔離級(jí)別。采用 READ COMMITTED 的默認(rèn)事務(wù)隔離級(jí)別時(shí),只在讀取頁(yè)的期間內(nèi)控制共享鎖。在掃描中,直到在掃描內(nèi)的下一頁(yè)上獲取鎖時(shí)才釋放鎖。如果指定 HOLDLOCK 提示或者將事務(wù)隔離級(jí)別設(shè)置為 REPEATABLE READ 或 SERIALIZABLE,則直到事務(wù)結(jié)束才釋放鎖。


根據(jù)為游標(biāo)設(shè)置的并發(fā)選項(xiàng),游標(biāo)可以獲取共享模式的滾動(dòng)鎖以保護(hù)提取。當(dāng)需要滾動(dòng)鎖時(shí),直到下一次提取或關(guān)閉游標(biāo)(以先發(fā)生者為準(zhǔn))時(shí)才釋放滾動(dòng)鎖。但是,如果指定 HOLDLOCK,則直到事務(wù)結(jié)束才釋放滾動(dòng)鎖。


用于保護(hù)更新的排它鎖將直到事務(wù)結(jié)束才釋放。?
如果一個(gè)連接試圖獲取一個(gè)鎖,而該鎖與另一個(gè)連接所控制的鎖沖突,則試圖獲取鎖的連接將一直阻塞到:?


將沖突鎖釋放而且連接獲取了所請(qǐng)求的鎖。


連接的超時(shí)間隔已到期。默認(rèn)情況下沒(méi)有超時(shí)間隔,但是一些應(yīng)用程序設(shè)置超時(shí)間隔以防止無(wú)限期等待?


五 ?SQL Server 中鎖的自定義?


1 處理死鎖和設(shè)置死鎖優(yōu)先級(jí)


死鎖就是多個(gè)用戶申請(qǐng)不同封鎖,由于申請(qǐng)者均擁有一部分封鎖權(quán)而又等待其他用戶擁有的部分封鎖而引起的無(wú)休止的等待


可以使用SET DEADLOCK_PRIORITY控制在發(fā)生死鎖情況時(shí)會(huì)話的反應(yīng)方式。如果兩個(gè)進(jìn)程都鎖定數(shù)據(jù),并且直到其它進(jìn)程釋放自己的鎖時(shí),每個(gè)進(jìn)程才能釋放自己的鎖,即發(fā)生死鎖情況。


2 ?處理超時(shí)和設(shè)置鎖超時(shí)持續(xù)時(shí)間。


@@LOCK_TIMEOUT 返回當(dāng)前會(huì)話的當(dāng)前鎖超時(shí)設(shè)置,單位為毫秒


SET LOCK_TIMEOUT 設(shè)置允許應(yīng)用程序設(shè)置語(yǔ)句等待阻塞資源的最長(zhǎng)時(shí)間。當(dāng)語(yǔ)句等待的時(shí)間大于 LOCK_TIMEOUT 設(shè)置時(shí),系統(tǒng)將自動(dòng)取消阻塞的語(yǔ)句,并給應(yīng)用程序返回"已超過(guò)了鎖請(qǐng)求超時(shí)時(shí)段"的 1222 號(hào)錯(cuò)誤信息


示例?
下例將鎖超時(shí)期限設(shè)置為 1,800 毫秒。
SET LOCK_TIMEOUT 1800


3) ?設(shè)置事務(wù)隔離級(jí)別。
參見(jiàn) http://expert.csdn.net/Expert/topic/1785/1785314.xml?temp=.3050501


4 ) ?對(duì) SELECT、INSERT、UPDATE 和 DELETE 語(yǔ)句使用表級(jí)鎖定提示。


5) ? 配置索引的鎖定粒度
可以使用 sp_indexoption 系統(tǒng)存儲(chǔ)過(guò)程來(lái)設(shè)置用于索引的鎖定粒度


六 ?查看鎖的信息


1 ? 執(zhí)行 EXEC SP_LOCK 報(bào)告有關(guān)鎖的信息
2 ? 查詢分析器中按Ctrl+2可以看到鎖的信息


七 ?使用注意事項(xiàng)


如何避免死鎖
1 使用事務(wù)時(shí),盡量縮短事務(wù)的邏輯處理過(guò)程,及早提交或回滾事務(wù);
2 設(shè)置死鎖超時(shí)參數(shù)為合理范圍,如:3分鐘-10分種;超過(guò)時(shí)間,自動(dòng)放棄本次操作,避免進(jìn)程懸掛;
3 優(yōu)化程序,檢查并避免死鎖現(xiàn)象出現(xiàn);
4 .對(duì)所有的腳本和SP都要仔細(xì)測(cè)試,在正是版本之前。
5 所有的SP都要有錯(cuò)誤處理(通過(guò)@error)
6 一般不要修改SQL SERVER事務(wù)的默認(rèn)級(jí)別。不推薦強(qiáng)行加鎖


解決問(wèn)題 如何對(duì)行 表 數(shù)據(jù)庫(kù)加鎖


八 ?幾個(gè)有關(guān)鎖的問(wèn)題


1 如何鎖一個(gè)表的某一行


SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED?


SELECT * FROM table ?ROWLOCK ?WHERE id = 1


2 鎖定數(shù)據(jù)庫(kù)的一個(gè)表


SELECT * FROM table WITH (HOLDLOCK)?


加鎖語(yǔ)句:
sybase:
? ? ? update 表 set col1=col1 where 1=0 ;
MSSQL:
? ? ? select col1 from 表 (tablockx) where 1=0 ;
oracle:
? ? ? LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖后其它人不可操作,直到加鎖用戶解鎖,用commit或rollback解鎖


幾個(gè)例子幫助大家加深印象
設(shè)table1(A,B,C)
A ? ?B ? ?C
a1 ? b1 ? c1
a2 ? b2 ? c2
a3 ? b3 ? c3


1)排它鎖
新建兩個(gè)連接
在第一個(gè)連接中執(zhí)行以下語(yǔ)句
begin tran
? update table1
? set A='aa'
? where B='b2'
? waitfor delay '00:00:30' ?--等待30秒
commit tran
在第二個(gè)連接中執(zhí)行以下語(yǔ)句
begin tran
? select * from table1
? where B='b2' ??
commit tran


若同時(shí)執(zhí)行上述兩個(gè)語(yǔ)句,則select查詢必須等待update執(zhí)行完畢才能執(zhí)行即要等待30秒


2)共享鎖
在第一個(gè)連接中執(zhí)行以下語(yǔ)句
begin tran
? select * from table1 holdlock -holdlock人為加鎖
? where B='b2'?
? waitfor delay '00:00:30' ?--等待30秒
commit tran


在第二個(gè)連接中執(zhí)行以下語(yǔ)句
begin tran
? select A,C from table1
? where B='b2'?
? update table1
? set A='aa'
? where B='b2' ??
commit tran


若同時(shí)執(zhí)行上述兩個(gè)語(yǔ)句,則第二個(gè)連接中的select查詢可以執(zhí)行
而update必須等待第一個(gè)事務(wù)釋放共享鎖轉(zhuǎn)為排它鎖后才能執(zhí)行 即要等待30秒


3)死鎖
增設(shè)table2(D,E)
D ? ?E
d1 ? e1
d2 ? e2
在第一個(gè)連接中執(zhí)行以下語(yǔ)句
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
??
在第二個(gè)連接中執(zhí)行以下語(yǔ)句
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


同時(shí)執(zhí)行,系統(tǒng)會(huì)檢測(cè)出死鎖,并中止進(jìn)程


老大,你這我也懂,,但你這是技術(shù),,我問(wèn)的是解決方案,,車票系統(tǒng)到底用的哪種方案


SQL code
樓主參考下這個(gè)...悲觀鎖
?
悲觀鎖定解決方案
我們只要對(duì)上邊的代碼做微小的改變就可以實(shí)現(xiàn)悲觀的鎖定.
?
declare @CardNo varchar(20)
Begin Tran
?
? ? ? ?-- ?選擇一張未使用的卡
? ? ? ? select top 1 @CardNo=F_CardNo
? ? ? ? from Card ? with (UPDLOCK) ?where F_Flag=0
? ? ? ? ?
? ? ? ? -- ?延遲50秒,模擬并發(fā)訪問(wèn).
? ? ? ? waitfor delay '000:00:50'
?
? ? ? ?-- ?把剛才選擇出來(lái)的卡進(jìn)行注冊(cè).
?
? ? ? ? update Card
? ? ? ? set F_Name=user,
? ? ? ? ? ? F_Time=getdate(),
? ? ? ? ? ? F_Flag=1
? ? ? ? where F_CardNo=@CardNo
?
commit
?
注意其中的區(qū)別了嗎?with(updlock),是的,我們?cè)诓樵兊臅r(shí)候使用了with (UPDLOCK)選項(xiàng),在查詢記錄的時(shí)候我們就對(duì)記錄加上了更新鎖,表示我們即將對(duì)次記錄進(jìn)行更新.注意更新鎖和共享鎖是不沖突的,也就是其他用戶還可以查詢此表的內(nèi)容,但是和更新鎖和排它鎖是沖突的.所以其他的更新用戶就會(huì)阻塞.如果我們?cè)诹硗庖粋€(gè)窗口執(zhí)行此代碼,同樣不加waifor delay子句.兩邊執(zhí)行完畢后,我們發(fā)現(xiàn)成功的注冊(cè)了兩張卡.可能我們已經(jīng)發(fā)現(xiàn)了悲觀鎖定的缺點(diǎn):當(dāng)一個(gè)用戶進(jìn)行更新的事務(wù)的時(shí)候,其他更新用戶必須排隊(duì)等待,即使那個(gè)用戶更新的不是同一條記錄.


到底什么時(shí)候開始其它用戶不能操作,A用戶點(diǎn)擊修改時(shí)還是用戶點(diǎn)確定重新去讀一次數(shù)據(jù)庫(kù)時(shí),


SQL code
--這里還有一個(gè)~ 之前保存的 - -出處在哪沒(méi)有記錄...很不好意思 作者請(qǐng)罵我吧...
?
樂(lè)觀鎖定解決方案
-- ?首先我們?cè)贑ard表里邊加上一列F_TimeStamp 列,該列是varbinary(8)類型.但是在更新的時(shí)候這個(gè)值會(huì)自動(dòng)增長(zhǎng).
?
alter table Card add ?F_TimeStamp timestamp not null
??
-- ?悲觀鎖定
declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int
?
Begin Tran
?
? ? ? ?-- ?取得卡號(hào)和原始的時(shí)間戳值
? ? ? ? select top 1 @CardNo=F_CardNo,
? ? ? ? ? ? ? ? ? ? ?@timestamp=F_TimeStamp
? ? ? ? from Card
? ? ? ? where F_Flag=0
? ? ? ? ?
? ? ? ? -- ?延遲50秒,模擬并發(fā)訪問(wèn).
? ? ? ? waitfor delay '000:00:50'
?
? ? ? ? -- ?注冊(cè)卡,但是要比較時(shí)間戳是否發(fā)生了變化.如果沒(méi)有發(fā)生變化.更新成功.如果發(fā)生變化,更新失敗.
?
? ? ? ? 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 '此卡已經(jīng)被另外一個(gè)用戶注冊(cè)!'
? ? ? ? ? ? ? ? ? ? ? ? rollback tran
? ? ? ? ? ? ? ? end
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? begin
? ? ? ? ? ? ? ? ? ? ? ? print '并不存在此卡!'
? ? ? ? ? ? ? ? ? ? ? ? rollback tran
? ? ? ? ? ? ? ? end
? ? ? ? end
?
在另外一個(gè)窗口里邊執(zhí)行沒(méi)有waitfor的代碼,注冊(cè)成功后,返回原來(lái)的窗口,我們就會(huì)發(fā)現(xiàn)到時(shí)間后它顯示的提示是此卡以被另外一個(gè)用戶注冊(cè)的提示.很明顯,這樣我們也可以避免兩個(gè)用戶同時(shí)注冊(cè)一張卡的現(xiàn)象的出現(xiàn).同時(shí),使用這種方法的另外一個(gè)好處是沒(méi)有使用更新鎖,這樣增加的系統(tǒng)的并發(fā)處理能力.


加個(gè)rowversion字段,每當(dāng)數(shù)據(jù)被修改時(shí),此字段會(huì)被UPDATE,
保存時(shí),判斷記錄是否已經(jīng)被修改。


看來(lái)LZ沒(méi)有做過(guò)實(shí)際案例啊,現(xiàn)在我給你透露下實(shí)際售票系統(tǒng)中的一個(gè)方案例子:


? ?首先沒(méi)有那么復(fù)雜的鎖,實(shí)際應(yīng)用會(huì)盡量從業(yè)務(wù)角度考慮避免沖突:


? ?實(shí)際售票系統(tǒng)是這樣:?
?
? ? ? ? ? ?1.售票中,"座位號(hào)" 才是競(jìng)爭(zhēng)資源;
? ? ? ? ? ?2.售票中,查看票是不發(fā)生鎖號(hào)的.
? ? ? ? ? ?3.售票中,有個(gè)選票(選座位號(hào))的動(dòng)作,選座位號(hào)確定時(shí),才發(fā)生鎖號(hào)(即鎖住改作為號(hào),即使這鎖號(hào),也只是修改標(biāo)記,表示自己暫時(shí)鎖住);
? ? ? ? ? ?4.等客戶交錢后,就確定提交交易完成,這時(shí)候,就成為售出該票了(當(dāng)然,被鎖的號(hào),要修改為對(duì)應(yīng)的已售標(biāo)記,及其他流程操作).


從這個(gè)過(guò)程看,幾乎沒(méi)有那么多沖突出現(xiàn)(只有選號(hào)時(shí),有可能已被別人選了,這也應(yīng)該知道的,可以另選號(hào)),這就是方案.


樂(lè)觀鎖定解決方案


-- ?首先我們?cè)贑ard表里邊加上一列F_TimeStamp 列,該列是varbinary(8)類型.但是在更新的時(shí)候這個(gè)值會(huì)自動(dòng)增長(zhǎng).


alter table Card add ?F_TimeStamp timestamp not null


-- ?悲觀鎖定
declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int


Begin Tran


? ? ? ?--…




你這是當(dāng)點(diǎn)確定后再去判斷是否卡否已被注冊(cè)了嘛,,我想知道車票出售系統(tǒng)或大型網(wǎng)絡(luò)版的管理系統(tǒng)的解決方案


利用小粒度鎖可以盡量避免沖突,分析好你的業(yè)務(wù),沒(méi)多少問(wèn)題。如7樓所言,一般的情況下,鎖使用并


看來(lái)LZ沒(méi)有做過(guò)實(shí)際案例啊,現(xiàn)在我給你透露下實(shí)際售票系統(tǒng)中的一個(gè)方案例子:


首先沒(méi)有那么復(fù)雜的鎖,實(shí)際應(yīng)用會(huì)盡量從業(yè)務(wù)角度考慮避免沖突:


實(shí)際售票系統(tǒng)是這樣:


1.售票中,"座位號(hào)" 才是競(jìng)爭(zhēng)資源;
2.售票中,查看票是不發(fā)生鎖號(hào)的.
3.售票中,有個(gè)選票(選座位號(hào))的動(dòng)作,選座位號(hào)確定時(shí),才發(fā)生鎖號(hào)(即鎖住改作為號(hào),即使這鎖號(hào),也只是修改標(biāo)記,表示自己暫時(shí)鎖住);
4.等客戶交錢后,就確定提交交易完成,這時(shí)候,就成為售出該…


同意,就是這個(gè)意思


看來(lái)LZ沒(méi)有做過(guò)實(shí)際案例啊,現(xiàn)在我給你透露下實(shí)際售票系統(tǒng)中的一個(gè)方案例子:?


? 首先沒(méi)有那么復(fù)雜的鎖,實(shí)際應(yīng)用會(huì)盡量從業(yè)務(wù)角度考慮避免沖突:?


? 實(shí)際售票系統(tǒng)是這樣:?


? ? ? ? ? 1.售票中,"座位號(hào)" 才是競(jìng)爭(zhēng)資源;?
? ? ? ? ? 2.售票中,查看票是不發(fā)生鎖號(hào)的.?
? ? ? ? ? 3.售票中,有個(gè)選票(選座位號(hào))的動(dòng)作,選座位號(hào)確定時(shí),才發(fā)生鎖號(hào)(即鎖住改作為號(hào),即使這鎖號(hào),也只是修改標(biāo)記,表示自己暫時(shí)鎖住);?
? ? ? ? ? 4.等…


謝謝,,,,,是不是在查看時(shí)去修改數(shù)據(jù)庫(kù)的記錄的一個(gè)標(biāo)記,,當(dāng)查看完了(取消或者售完票后)再將這個(gè)標(biāo)記修改回去,,,


有誰(shuí)知道怎樣導(dǎo)入Excel何導(dǎo)入Word


SQL code


begin tran ?
set transaction isolation level serializable?
update zjk set zjye =zjye-100 where zjzh ='1234567890'
commit tran ?


以上代碼,使用隔離級(jí)別serializable ,即1語(yǔ)句不能讀取已由其他事務(wù)修改但尚未提交的數(shù)據(jù)。
2任何其他事務(wù)都不能在當(dāng)前事務(wù)完成之前修改由當(dāng)前事務(wù)讀取的數(shù)據(jù)。
3在當(dāng)前事務(wù)完成之前,其他事務(wù)不能使用當(dāng)前事務(wù)中任何語(yǔ)句讀取的鍵值插入新行。
參考http://msdn.microsoft.com/zh-cn/express/ms173763(SQL.90).aspx


加個(gè)rowversion字段,每當(dāng)數(shù)據(jù)被修改時(shí),此字段會(huì)被UPDATE,?
保存時(shí),判斷記錄是否已經(jīng)被修改。


又來(lái)了,,我問(wèn)的是解決方案,,不是技術(shù),,,


用7樓的方案就行了,
查詢不鎖,進(jìn)一步確認(rèn)時(shí)臨時(shí)鎖,確認(rèn)買客戶交錢后更新已售,否則取消鎖


你的問(wèn)題跟火車票不太一樣的。


對(duì)于你的問(wèn)題,需要解決的是如何處理更新沖突


傳統(tǒng)方式,都是用 update XXXX set xxx where 主鍵=XXX
而使用沖突檢查,則需要用 update XXXX set xxx where 主鍵=XXX and 修改過(guò)的字段1=原始值 and 修改過(guò)的字段2=原始值……


如果update沒(méi)有更新數(shù)據(jù),則這條數(shù)據(jù)不是被其它用戶修改了,就是被刪除了


看來(lái)LZ沒(méi)有做過(guò)實(shí)際案例啊,現(xiàn)在我給你透露下實(shí)際售票系統(tǒng)中的一個(gè)方案例子:?


? 首先沒(méi)有那么復(fù)雜的鎖,實(shí)際應(yīng)用會(huì)盡量從業(yè)務(wù)角度考慮避免沖突:?


? 實(shí)際售票系統(tǒng)是這樣:?


? ? ? ? ? 1.售票中,"座位號(hào)" 才是競(jìng)爭(zhēng)資源;?
? ? ? ? ? 2.售票中,查看票是不發(fā)生鎖號(hào)的.?
? ? ? ? ? 3.售票中,有個(gè)選票(選座位號(hào))的動(dòng)作,選座位號(hào)確定時(shí),才發(fā)生鎖號(hào)(即鎖住改作為號(hào),即使這鎖號(hào),也只是修改標(biāo)記,表示自己暫時(shí)鎖住);?
? ? ? ? ? 4.等…


關(guān)鍵是第三步。我理解買票的時(shí)候雖然外面只是一個(gè)買入鍵的敲擊動(dòng)作,但后臺(tái)應(yīng)該是分為1、鎖定當(dāng)前記錄,2、鎖定成功后修改該票屬性 兩個(gè)動(dòng)作的。只有第一個(gè)動(dòng)作成功,才能做第二個(gè)動(dòng)作。
我傾向于不是用SQL語(yǔ)句來(lái)鎖住某行,而是在該行有某字段,修改成功就表示鎖定。鎖表對(duì)性能有影響。


我也覺(jué)得應(yīng)該是第三步,,但我細(xì)節(jié)我不贊成,,我認(rèn)為,選票時(shí),鎖定該記錄(不一定非要用鎖,可以加一個(gè)字段鎖定,此時(shí)將它改為鎖定狀態(tài),)當(dāng)客戶交錢提交交易完成 時(shí),再改該記錄的已售狀態(tài),當(dāng)取消交易時(shí),,再把鎖定改為非鎖定狀態(tài),,,不知道理解對(duì)沒(méi)


這個(gè)問(wèn)題也遇到過(guò)


如果不用鎖,,去改鎖定字段時(shí),好像也有問(wèn)題,,當(dāng)去修改鎖定字段為鎖定狀態(tài)時(shí),,此時(shí)要是機(jī)了重啟了,,那不是一直在鎖定


? "如果不用鎖,,去改鎖定字段時(shí),好像也有問(wèn)題,,當(dāng)去修改鎖定字段為鎖定狀態(tài)時(shí),,此時(shí)要是機(jī)了重啟了,,那不是一直在鎖定"


說(shuō)的沒(méi)錯(cuò),既然是兩階段提交,自然有可能發(fā)生意外在中間過(guò)程中,


象你說(shuō)的中途死機(jī)了,這個(gè)需要解決的,實(shí)際中當(dāng)然會(huì)考慮周全的,有另外解決之道.
所以說(shuō),這是個(gè)工程,有系列問(wèn)題要解決.?


如果是死機(jī),可以有方案解決(這個(gè)可以自己考慮,各公司可能策略不同),簡(jiǎn)單的方法是, 客戶端有緩存日志記錄,如果死機(jī),啟動(dòng)的時(shí)候,自然會(huì)知道上次未完成的事情; 當(dāng)然,如果有好方案也可以在后臺(tái)來(lái)解決.總之這個(gè)就很多途徑.


SQL code
rowversion 字段
在更新前獲取該字段的值,更新是在比較該值是否相當(dāng)。OK。


似乎也可以理解為事物的ID號(hào)。


七樓的又來(lái)了,,能不能留個(gè)QQ號(hào)嘛,,,我想知道細(xì)節(jié),,,,


不知道 '伽楠居士' 是研究,還是要開發(fā)實(shí)際業(yè)務(wù)系統(tǒng).


? ?QQ:16258699 (不一定實(shí)時(shí)都在)


開發(fā)實(shí)際的業(yè)務(wù)系統(tǒng)


合格各方的后


1、查詢時(shí)不需要鎖;
2、執(zhí)行時(shí)需要驗(yàn)證,可在一個(gè)事務(wù)中處理;
即真正需要解決的是在執(zhí)行階段,表象為:
查詢的時(shí)候,票還在,出票瞬間,可能已經(jīng)沒(méi)有票了,即交易不成功。
售票系統(tǒng)最好不要加鎖,耗資源且出了異常需要專門處理(手動(dòng)釋放鎖)


設(shè)計(jì)多一個(gè)標(biāo)志字段,在“當(dāng)用戶點(diǎn)修改時(shí)”,讀出數(shù)據(jù)(讀未標(biāo)志記錄)同時(shí)修改標(biāo)志,表示“我正在修改這條記錄,其它人不能讀”
如果編輯后保存,保存就可以了
如果編輯后取消,將標(biāo)志改回,表示“我放棄這條記錄,其它人可以讀”


這種標(biāo)志是常用的設(shè)計(jì)


http://jone33.download.csdn.net/ ? 資源不錯(cuò),文檔很多。


謝謝大家,,結(jié)了,
========

數(shù)據(jù)庫(kù) 事務(wù)并發(fā)控制

事務(wù)是一個(gè)邏輯工作單元,SQL Server 2005 提供了幾種自動(dòng)的可以通過(guò)編程來(lái)完成的機(jī)制,包括事務(wù)日志、SQL事務(wù)控制語(yǔ)句,以及事務(wù)處理運(yùn)行過(guò)程中通過(guò)鎖定保證數(shù)據(jù)完整性的機(jī)制。當(dāng)用戶對(duì)數(shù)據(jù)庫(kù)并發(fā)訪問(wèn)時(shí),為了確保事務(wù)完整性和數(shù)據(jù)庫(kù)一致性,需要使用鎖定。事務(wù)和鎖是兩個(gè)緊密聯(lián)系的概念。通過(guò)事務(wù)、批和鎖的使用,還可以監(jiān)測(cè)系統(tǒng),以及優(yōu)化物理數(shù)據(jù)庫(kù)。作業(yè)是一種多步執(zhí)行的任務(wù)。


本章主要介紹 SQL Server 2005數(shù)據(jù)庫(kù)系統(tǒng)的事務(wù)和鎖的基本概念,事務(wù)、批、鎖的創(chuàng)建和使用,通過(guò)事務(wù)、批、鎖監(jiān)測(cè)系統(tǒng)和優(yōu)化物理數(shù)據(jù)庫(kù)的操作,以及作業(yè)的設(shè)置。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?12.1 事物的基本概念和SQL Server 2005事物處理
事務(wù)和存儲(chǔ)過(guò)程類似,由一系列T-SQL語(yǔ)句組成,是 SQL Server 2005系統(tǒng)的執(zhí)行單元。本節(jié)主要介紹 SQL Server 2005中事務(wù)的概念,以及事務(wù)的創(chuàng)建、使用。


12.1.1 事務(wù)概述
關(guān)系型數(shù)據(jù)庫(kù)有4個(gè)顯著的特征:安全性、完整性、檢測(cè)性和并發(fā)性。數(shù)據(jù)庫(kù)的安全性就是要保證數(shù)據(jù)庫(kù)數(shù)據(jù)的安全,防止未授權(quán)用戶隨意修改數(shù)據(jù)庫(kù)中的數(shù)據(jù),確保數(shù)據(jù)的安全。完整性是數(shù)據(jù)庫(kù)的一個(gè)重要特征,也是保證數(shù)據(jù)庫(kù)中的數(shù)據(jù)切實(shí)有效、防止錯(cuò)誤、實(shí)現(xiàn)商業(yè)規(guī)則的一種重要機(jī)制。在數(shù)據(jù)庫(kù)中,區(qū)別所保存的數(shù)據(jù)是無(wú)用的垃圾還是有價(jià)值的信息,主要是依據(jù)數(shù)據(jù)庫(kù)的完整性是否健全,即實(shí)體完整性、域完整性和參考完整性。對(duì)任何發(fā)現(xiàn)影響系統(tǒng)性能的因素和瓶頸,采取切合實(shí)際的策略,解決問(wèn)題,提高系統(tǒng)的性能。并發(fā)性是用來(lái)解決多個(gè)用戶對(duì)同一數(shù)據(jù)進(jìn)行操作時(shí)的問(wèn)題。特別是對(duì)于網(wǎng)絡(luò)數(shù)據(jù)庫(kù)來(lái)說(shuō),這個(gè)特點(diǎn)更加突出。提高數(shù)據(jù)庫(kù)的處理速度,單單依靠提高計(jì)算機(jī)的物理速度是不夠的,還必須充分考慮數(shù)據(jù)庫(kù)的并發(fā)性問(wèn)題,提高數(shù)據(jù)庫(kù)并發(fā)性的效率。


那么如何保證并發(fā)性呢?在 SQL Server 2005中,通過(guò)使用事務(wù)和鎖機(jī)制,可以解決數(shù)據(jù)庫(kù)的并發(fā)性問(wèn)題。


在 SQL Server 2005中,事務(wù)要求處理時(shí)必須滿足ACID原則,即原子性(A)、一致性(C)、隔離性(I)和持久性(D)。


原子性:原子性也稱為自動(dòng)性,是指事務(wù)必須執(zhí)行一個(gè)完整的工作,要么執(zhí)行全部數(shù)據(jù)的操作,要么全部不執(zhí)行。


一致性:一致性是指當(dāng)事務(wù)完成時(shí),必須所有的數(shù)據(jù)具有一致的狀態(tài)。


隔離性


隔離性:也稱為獨(dú)立性,是指并行事務(wù)的修改必須與其他并行事務(wù)的修改相互獨(dú)立。一個(gè)事務(wù)處理數(shù)據(jù),要么是其他事務(wù)執(zhí)行之前的狀態(tài),要么是其他事務(wù)執(zhí)行之后的狀態(tài),但不能處理其他正在處理的數(shù)據(jù)。


持久性


持久性:是指當(dāng)一個(gè)事務(wù)完成之后,將影響永久性地存于系統(tǒng)中,即事務(wù)的操作將寫入數(shù)據(jù)庫(kù)中。


事務(wù)的這種機(jī)制保證了一個(gè)事務(wù)或者提交后成功執(zhí)行,或者提交后失敗回滾,二者必居其一,因此,事務(wù)對(duì)數(shù)據(jù)的修改具有可恢復(fù)性,即當(dāng)事務(wù)失敗時(shí),它對(duì)數(shù)據(jù)的修改都會(huì)恢復(fù)到該事務(wù)執(zhí)行前的狀態(tài)。而使用一般的批處理,則有可能出現(xiàn)有的語(yǔ)句被執(zhí)行,而另一些語(yǔ)句沒(méi)有被執(zhí)行的情況,從而有可能造成數(shù)據(jù)不一致。


事務(wù)開始之后,事務(wù)所有的操作都陸續(xù)寫到事務(wù)日志中。這些任務(wù)操作在事務(wù)日志中記錄一個(gè)標(biāo)志,用于表示執(zhí)行了這種操作,當(dāng)取消這種事務(wù)時(shí),系統(tǒng)自動(dòng)執(zhí)行這種操作的反操作,保證系統(tǒng)的一致性。系統(tǒng)自動(dòng)生成一個(gè)檢查點(diǎn)機(jī)制,這個(gè)檢查點(diǎn)周期地發(fā)生。檢查點(diǎn)的周期是系統(tǒng)根據(jù)用戶定義的時(shí)間間隔和系統(tǒng)活動(dòng)的頻度由系統(tǒng)自動(dòng)計(jì)算出來(lái)的時(shí)間間隔。檢查點(diǎn)周期地檢查事物日志,如果在事務(wù)日志中,事務(wù)全部完成,那么檢查點(diǎn)將事務(wù)提交到數(shù)據(jù)庫(kù)中,并且在事務(wù)日志中做一個(gè)檢查點(diǎn)提交標(biāo)記。如果在事務(wù)日志中,事務(wù)沒(méi)有完成,那么檢查點(diǎn)將事務(wù)日志中的事務(wù)不提交到數(shù)據(jù)庫(kù)中,并且在事務(wù)日志中做一個(gè)檢查點(diǎn)未提交標(biāo)記。


12.1.2 事務(wù)的類型
根據(jù)事務(wù)的設(shè)置、用途的不同,SQL Server 2005將事務(wù)分為多種類型。


1. 根據(jù)系統(tǒng)的設(shè)置分類
根據(jù)系統(tǒng)的設(shè)置,SQL Server 2005將事務(wù)分為兩種類型:系統(tǒng)提供的事務(wù)和用戶定義的事務(wù),分別簡(jiǎn)稱為系統(tǒng)事務(wù)和用戶定義事務(wù)。


(1)系統(tǒng)事務(wù)
系統(tǒng)提供的事務(wù)是指在執(zhí)行某些語(yǔ)句時(shí),一條語(yǔ)句就是一個(gè)事務(wù)。但是要明確,一條語(yǔ)句的對(duì)象既可能是表中的一行數(shù)據(jù),也可能是表中的多行數(shù)據(jù),甚至是表中的全部數(shù)據(jù)。


因此,只有一條語(yǔ)句構(gòu)成的事務(wù)也可能包含了多行數(shù)據(jù)的處理。


系統(tǒng)提供的事務(wù)語(yǔ)句如下:


ALTER TABLE 、CREATE、DELETE、DROP、FETCH、GRANT、INSERT、OPEN、REBOKE、SELECT、UPDATE、TRUNCATE TABLE


這些語(yǔ)句本身就構(gòu)成了一個(gè)事務(wù)。


例12-1使用CREATE TABLE創(chuàng)建一個(gè)表。


      CREATE TABLE student


? ? ? ? ? ? (id CHAR(10),


? ? ? ? ? ? name CHAR(6),


? ? ? ? ? ? sex CHAR(2)


? ? ? ? ? ? )


說(shuō)明:這條語(yǔ)句本身就構(gòu)成了一個(gè)事務(wù)。這條語(yǔ)句由于沒(méi)有使用條件限制,那么這條語(yǔ)句就是創(chuàng)建包含3個(gè)列的表。要么創(chuàng)建全部成功,要么全部失敗。


(2)用戶定義事務(wù)
在實(shí)際應(yīng)用中,大多數(shù)的事務(wù)處理采用了用戶定義的事務(wù)來(lái)處理。在開發(fā)應(yīng)用程序時(shí),可以使用BEGIN TRANSACTION語(yǔ)句來(lái)定義明確的用戶定義的事務(wù)。在使用用戶定義的事務(wù)時(shí),一定要注意事務(wù)必須有明確的結(jié)束語(yǔ)句來(lái)結(jié)束。如果不使用明確的結(jié)束語(yǔ)句來(lái)結(jié)束,那么系統(tǒng)可能把從事務(wù)開始到用戶關(guān)閉連接之間的全部操作都作為一個(gè)事務(wù)來(lái)對(duì)待。事務(wù)的明確結(jié)束可以使用兩個(gè)語(yǔ)句中的一個(gè):COMMIT語(yǔ)句和ROLLBACK語(yǔ)句。COMMIT語(yǔ)句是提交語(yǔ)句,將全部完成的語(yǔ)句明確地提交到數(shù)據(jù)庫(kù)中。ROLLBACK語(yǔ)句是取消語(yǔ)句,該語(yǔ)句將事務(wù)的操作全部取消,即表示事務(wù)操作失敗。


還有一種特殊的用戶定義的事務(wù),這就是分布式事務(wù)。例12-1事務(wù)是在一個(gè)服務(wù)器上的操作,其保證的數(shù)據(jù)完整性和一致性是指一個(gè)服務(wù)器上的完整性和一致性。但是,如果一個(gè)比較復(fù)雜的環(huán)境,可能有多臺(tái)服務(wù)器,那么要保證在多臺(tái)服務(wù)器環(huán)境中事務(wù)的完整性和一致性,就必須定義一個(gè)分布式事務(wù)。在這個(gè)分布式事務(wù)中,所有的操作都可以涉及對(duì)多個(gè)服務(wù)器的操作,當(dāng)這些操作都成功時(shí),那么所有這些操作都提交到相應(yīng)服務(wù)器的數(shù)據(jù)庫(kù)中,如果這些操作中有一個(gè)操作失敗,那么這個(gè)分布式事務(wù)中的全部操作都將被取消。


2. 根據(jù)運(yùn)行模式分類
根據(jù)運(yùn)行模式,SQL Server 2005將事務(wù)分為4種類型:自動(dòng)提交事務(wù)、顯示事務(wù)、隱式事務(wù)和批處理級(jí)事務(wù)。


(1)自動(dòng)提交事務(wù)
自動(dòng)提交事務(wù)是指每條單獨(dú)的語(yǔ)句都是一個(gè)事務(wù)。


(2)顯式事務(wù)
顯式事務(wù)指每個(gè)事務(wù)均以BEGIN TRANSACTION語(yǔ)句顯式開始,以COMMIT或ROLLBACK語(yǔ)句顯示結(jié)束。


(3)隱式事務(wù)
隱式事務(wù)指在前一個(gè)事務(wù)完成時(shí)新事務(wù)隱式啟動(dòng),但每個(gè)事務(wù)仍以COMMIT或ROLLBACK語(yǔ)句顯式完成。


(4)批處理級(jí)事務(wù)
該事務(wù)只能應(yīng)用于多個(gè)活動(dòng)結(jié)果集(MARS),在MARS會(huì)話中啟動(dòng)的T-SQL顯式或隱式事務(wù)變?yōu)榕幚砑?jí)事務(wù)。當(dāng)批處理完成時(shí),沒(méi)有提交或回滾的批處理級(jí)事務(wù)自動(dòng)由SQL Server語(yǔ)句集合分組后形成單個(gè)的邏輯工作單元。


3. 事務(wù)處理語(yǔ)句
BEGIN TRANSAVTION語(yǔ)句。


COMMIT TRANSACTION語(yǔ)句。


ROLLBACK TRANSACTION語(yǔ)句。


SAVE TRANSACTION語(yǔ)句。


(1)BEGIN TRANSECTION 語(yǔ)句
BEGIN TRANSACTION?語(yǔ)句定義渀個(gè)顯式本地事務(wù)的起點(diǎn),即事務(wù)纄開始。其語(yǔ)法格式為:


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’}}


]??]


說(shuō)昞゙


T?A?SAC?ION關(guān)鍵字可仧縮寫TRAN?*Trcnsac|恩on_namg虧務(wù)唍,PTREN_?EME_warieble是用戶定義盄?含有敨事勡名秴的變量,該變量必頓是字符數(shù)據(jù)類型?????X耠?ARK指定在查志中標(biāo)記事?,d?skrmp?ion是描述該栗記的字符串?


(2)COMMIT UR?N[聉CTIO??誤句
C_MOIT ?RANSKC?MON語(yǔ)句標(biāo)志一個(gè)爐功的隱緶?zhǔn)聞?wù)樞顯式享嚡皌結(jié)束。啶語(yǔ)法格式人:


COMMIU{TRA??TSAN?ACTION}?tò??sact?on?nem?|??ran_na?e_?arkab?補(bǔ)?]???]


誒明:僅當(dāng)事務(wù)被引用所有數(shù)據(jù)的鄻輯都正籮時(shí),T-SQL語(yǔ)句才庴發(fā)出COMMIT"T?ANS?C?IO?(命濾あ當(dāng)在嵍套事務(wù)中使用時(shí),妅部事務(wù)皤提交并不釋放資澐或使其修改成為縸久修改?只有在提令了外部事務(wù)曠,數(shù)歮修改扭?有永久悧,而且資源捍會(huì)被釋放。當(dāng)A@U?aN[O?NT?大侎1痶,每?一個(gè)CMMIT ?TRANSACT?ON 命仦只會(huì)使@@TR?nK?U?T(按1逳凱瀃當(dāng)A@?VANC?UNTY0 最終逓?伺0時(shí),將提交整個(gè)外部些務(wù)?


(3)VOLMCA?K "TRANSCCtIO^ 語(yǔ)句
?OьLт?C??`TRAю?ACT?ON! 語(yǔ)埥將顯示事務(wù)或隱藏事務(wù)皔起點(diǎn)戶事務(wù)內(nèi)皌某個(gè)保存點(diǎn),它也標(biāo)志七個(gè)庋務(wù)盄結(jié)束。其語(yǔ)泗格彏如下:??O??BICK?Р?TRA??TRANsA?TíON}??tra?sakti?n??a?e|@vrao_n?me_varmafle?s??epo?~t?name|@savepoi??variable][??


說(shuō)明:?OL??A?K ?VRANSA?TIO^0清除自事劣皅起點(diǎn)或到某丫保存點(diǎn)所有數(shù)據(jù)修敹。它還釋放由事務(wù)控制的資源。Sq?epoi?t_name是S??E !?RC?SA??I?NР 語(yǔ)句中的sawepoint_oame。當(dāng)條件回滾庖只彳哭事務(wù)的一郪分時(shí)<可以使甪óa(chǎn)v??oi???nameㄒсsaw?po?nt?聶ari?cle港用戶實(shí)義的、包含朩效保存點(diǎn)名稱的變駏的唍稱-忕駐是字符敺據(jù)類型。儍?AW?d Tò?NS?C\ION語(yǔ)寥


SAVE)(T?ANSACT??~語(yǔ)句在事務(wù)內(nèi)設(shè)置保存點(diǎn)。其語(yǔ)法格式為:


SAVE ?{TVAN ??TRQOSAC\I?^]{?avepo?nt??am?|A?avepoint_??riable}[;y


說(shuō)明:用爺可以在溟務(wù)內(nèi)設(shè)置保存點(diǎn)或標(biāo)記?保存熹可?實(shí)義在挏杣件受涍矒個(gè)介助的乀部切后,該事犡可以迖回的一個(gè)住置〆如果將事務(wù)回滾匰保存碹,則根據(jù)需覇必頓完戒其廗噩余皤T-SQR!迭句和C聏M?IV TRANSACTKON 語(yǔ)句-或者必須逞過(guò)將事務(wù)回滛到起始炻完全取消事嚡。若要取涉整個(gè)例務(wù),請(qǐng)用R?MNB?CK TR?N?aCTI?N t胲ansact}on?na?mР語(yǔ)句。違將撥消事務(wù)的所朋語(yǔ)叭和過(guò)程。聓av?ro?nt??a??是分配給忝存猶的名稱も@savetoént_variable包咫有效保存炻名稱的瞨戶定義變量的唍秱。


供1′?′ 寚義丄個(gè)事務(wù),帆扈有鑉濮了耳號(hào)?筋皆學(xué)生的嬆杰動(dòng)1?分,并毐交該事務(wù)。


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成績(jī)表


SET 分?jǐn)?shù)=切數(shù)+10


WшERE耠課稏號(hào)=3?O


CO?MI? TRANSQ??ION @t_n??g


g?$


說(shuō)明:漬例使甬0B?聇IN?Tz?NSA\KO? ?定義了一為事務(wù)名為 a?d_score的事務(wù),之后使用C?Mō]?"?RANWAC?IO? 提交,即行該事務(wù),將所有學(xué)生瞅分敲勱18分〢


徛q?=3定義丂個(gè)事務(wù),向庫(kù)存零仾表中添加一潡辴錄-并設(shè)置忝存碹。然后再剠除該記錄,幷回滺到介務(wù)盄保存點(diǎn),提交迥事厡。


B聅?IN ???ANSA?TiN0


I?_EST ??NTO數(shù)杮庫(kù)雷件表-VAьUES(?6007’,?辺?釘’,100l‘黑’,20)??AVE ?T?ANSICTI? s?vepoin?(-EEL?TE?FRoM 庫(kù)孫零件表


WHERE 零件編號(hào)=‘20007’


ROLLBACK ?TRANSACTION savepoint


COMMIT ?TRANSACTION


GO


說(shuō)明:本例使用BEGIN TRANSACTION定義了一個(gè)事務(wù),向表添加一條記錄,并設(shè)置保存點(diǎn)savepoint.之后再刪除該記錄,并回滾到事務(wù)的保存點(diǎn)savepoint處,使用COMMIT TRANSACTION 提交。結(jié)果該記錄沒(méi)有刪除。


例12-4定義一個(gè)事務(wù),向?qū)W生表中添加記錄。如果添加成功,則給每個(gè)分?jǐn)?shù)加10分。否則不操作。


BEGIN ?TRAN


INSERT INTO ?學(xué)生表


VALUES(‘234’,‘張’,‘男’,‘1980-10-28’,‘1’,‘3’,null)


IF @@ error=0


? ?BEGIN


PRINT ‘添加成功!’


UPDATE 成績(jī)表


SET分?jǐn)?shù)=分?jǐn)?shù)+10


WHERE 學(xué)號(hào)=111


COMMIT TRAN


END


? ?ELSE


BEGIN


? PRINT‘添加失敗!’


? ROLLBACK ?TRAN


END


12.1.3 事務(wù)和批
如果用戶希望或者整個(gè)操作完成,或者什么都不做,這時(shí)解決問(wèn)題的方法就是將整個(gè)操作組織成一個(gè)簡(jiǎn)單的事務(wù)處理,稱為批處理或批。


例12-5將多個(gè)操作定義為一個(gè)事務(wù)。


BEGIN ?TRANSACTION


UPDATE 成績(jī)表


SET 分?jǐn)?shù)=分?jǐn)?shù)+10


WHERE 課程號(hào)=5


INSERT INTO 學(xué)生表(學(xué)號(hào),姓名)


VALUES(20123,‘張全’)


DELETE FROM 課程表


WHERE 課程表


WHERE 課程名 LIKE ‘?dāng)?shù)%’


COMMIT TRANSACTION


說(shuō)明:本例將多個(gè)SQR操作定義為一個(gè)事務(wù),這時(shí)就形成了一個(gè)批處理,要么全部執(zhí)行,要么都不執(zhí)行。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?12.2 并發(fā)控制的基本概念和SQL Server 2005的并發(fā)控制機(jī)制
鎖就是防止其他事務(wù)訪問(wèn)指定資源的手段。鎖是實(shí)現(xiàn)并發(fā)控制的主要方法,是多個(gè)用戶能夠同時(shí)操縱同一個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)而不發(fā)生數(shù)據(jù)不一致現(xiàn)象的重要保障。


12.2.1 鎖概述
一般來(lái)說(shuō),鎖可以防止臟讀、不可重復(fù)讀和幻覺(jué)讀。臟讀就是指當(dāng)一個(gè)事務(wù)正在訪問(wèn)數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒(méi)有提交到數(shù)據(jù)庫(kù)中,這時(shí),另外一個(gè)事務(wù)也訪問(wèn)這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。因?yàn)檫@個(gè)數(shù)據(jù)是還沒(méi)有提交的數(shù)據(jù),那么另外嚴(yán)格事務(wù)讀到這個(gè)數(shù)據(jù)就是臟數(shù)據(jù),依據(jù)臟數(shù)據(jù)所做的操作可能是不正確的。不可重復(fù)讀是指在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒(méi)有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問(wèn)該數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,則第一個(gè)事務(wù)兩次讀到的數(shù)據(jù)可能是不一樣的。這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此,稱為不可重復(fù)讀。幻覺(jué)讀是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還沒(méi)有修改的數(shù)據(jù)行,就好像發(fā)生了幻覺(jué)一樣。


鎖是防止其他事務(wù)訪問(wèn)指定的資源控制、實(shí)現(xiàn)并發(fā)控制的一種手段。為了提高系統(tǒng)的性能、加快事務(wù)的處理速度、縮短事務(wù)的等待時(shí)間,應(yīng)該使鎖定的資源最小化。為了控制鎖定的資源,應(yīng)該首先了解系統(tǒng)的空間管理。在SQR SERVER 2005中,最小空間管理單位是頁(yè),一個(gè)頁(yè)有8KB。所有的數(shù)據(jù)、日志、索引都存放在頁(yè)上。另外,使用頁(yè)有一個(gè)限制,這就是表中的一行數(shù)據(jù)必須在同一個(gè)頁(yè)上。另外,使用頁(yè)有一個(gè)限制,這就是表中的一行數(shù)據(jù)必須在同一個(gè)頁(yè)上,不能跨頁(yè)。頁(yè)上面的空間管理單位是簇,一個(gè)簇是8個(gè)連續(xù)的頁(yè)。表和索引的最小占用單位是簇。數(shù)據(jù)庫(kù)是有一個(gè)或多個(gè)表或者索引組成,即有多個(gè)簇組成。


12.2.2 鎖的模式
數(shù)據(jù)庫(kù)引擎使用不同的鎖定資源,這些鎖模式確定了并發(fā)事務(wù)訪問(wèn)資源的方式。根據(jù)鎖定資源方式的不同,SQR SERVER 2005 提供了4種鎖模式:共享鎖、排他鎖、更新鎖,意向鎖。


1. 共享鎖
共享鎖也稱為S鎖,允許并行事務(wù)讀取同一種資源,這時(shí)的事務(wù)不能修改訪問(wèn)的數(shù)據(jù)。當(dāng)使用共享鎖鎖定資源時(shí),不允許修改數(shù)據(jù)的事務(wù)訪問(wèn)數(shù)據(jù)。當(dāng)讀取數(shù)據(jù)的事務(wù)讀完數(shù)據(jù)之后,立即釋放所占用的資源。一般地,當(dāng)使用SELECT 語(yǔ)句訪問(wèn)數(shù)據(jù)時(shí),系統(tǒng)自動(dòng)對(duì)所訪問(wèn)的數(shù)據(jù)使用共享鎖鎖定。


2. 排他鎖
對(duì)于那些修改數(shù)據(jù)的事務(wù),例如,使用INSERT、UPDATE、DELETE語(yǔ)句 ,系統(tǒng)自動(dòng)在所修改的事務(wù)上放置排他鎖。排他鎖也稱X鎖,就是在同一時(shí)間內(nèi)只允許一個(gè)事務(wù)訪問(wèn)一種資源,其他事務(wù)都不能在有排他鎖的資源上訪問(wèn)。在有排他鎖的資源上,不能放置共享鎖,也就是說(shuō),不允許可以產(chǎn)生共享鎖的事務(wù)訪問(wèn)這些資源。只有當(dāng)產(chǎn)生排他鎖的事務(wù)結(jié)束之后,排他鎖鎖定的資源才能被其他事務(wù)使用。


3. 更新鎖
更新鎖也稱為U鎖,可以防止常見(jiàn)的死鎖。在可重復(fù)讀或可序化事務(wù)中,此事務(wù)讀取數(shù)據(jù),獲取資源的共享鎖,然后修改數(shù)據(jù)。此操作要求鎖轉(zhuǎn)換為排鎖。如果兩個(gè)事務(wù)獲取了資源上的共享模式鎖,然后試圖同時(shí)更新數(shù)據(jù),則一個(gè)事務(wù)嘗試將鎖轉(zhuǎn)換為排他鎖。共享模式到排他鎖的轉(zhuǎn)換必須等待一段時(shí)間,因?yàn)橐粋€(gè)事務(wù)的排他鎖與其他事務(wù)的共享模式鎖不兼容,發(fā)生鎖等待。第二個(gè)事務(wù)試圖獲取排他鎖以進(jìn)行更新。由于兩個(gè)事務(wù)都要轉(zhuǎn)換為排他鎖,并且每個(gè)事務(wù)都等待另一個(gè)事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。


若要避免這種潛在的死鎖問(wèn)題,請(qǐng)使用更新鎖。一次只有一個(gè)事務(wù)可以獲得資源的更新鎖。如果事務(wù)修改資源,則更新鎖轉(zhuǎn)換為排他鎖。


4. 意向鎖
數(shù)據(jù)庫(kù)引擎使用意向鎖來(lái)保護(hù)共享鎖或排他鎖放置在鎖層次結(jié)構(gòu)的底層資源上。之所以命名為意向鎖,是因?yàn)樵谳^低級(jí)別鎖前可獲取它們,因此,會(huì)通知意向?qū)㈡i放置在較低級(jí)別上。意向鎖有兩種用途:


防止其他事務(wù)以會(huì)使較低級(jí)別的鎖無(wú)效的方式修改較高級(jí)別資源。


提高數(shù)據(jù)庫(kù)引擎在較高的粒度級(jí)別檢測(cè)鎖沖突的效率。


意向鎖又分為意向共享鎖(IS)、意向排他鎖(IX)、以及意向排他共享鎖(SIX)。意向共享鎖表示讀低層次資源的事務(wù)的意向,把共享鎖放在這些單個(gè)的資源上。意向排他鎖表示修改低層次的事務(wù)的意向,把排他鎖放在這些單個(gè)資源上。意向排他鎖包括意向共享鎖,它是意向共享鎖的超集。使用意向排他的共享鎖表示允許并行讀取頂層資源的事務(wù)的意向,并且修改一些低層次的資源,把意向排他鎖這些單個(gè)資源上。例如,表上的一個(gè)使用意向排他的共享鎖把共享鎖放在表上,允許并行讀取,并且把意向排他鎖放在剛要修改的頁(yè)上,把排他鎖放在修改的行上。每一個(gè)表一次只能有一個(gè)使用意向排他的共享鎖因?yàn)楸砑?jí)共享鎖阻止對(duì)表的任何修改。使用意向排他的共享鎖和意向排他鎖的組合。


12.2.3 鎖的信息
鎖兼容性控制多個(gè)事務(wù)能否同時(shí)獲取同一資源上的鎖。如果資源已被另一事務(wù)鎖定,則,僅當(dāng)請(qǐng)求鎖的模式與現(xiàn)有鎖的模式兼容時(shí),才會(huì)授予新的鎖請(qǐng)求。如果請(qǐng)求鎖的模式與現(xiàn)有的模式不兼容,則請(qǐng)求新鎖的事務(wù)將等待釋放現(xiàn)有鎖或等待鎖超時(shí)間隔過(guò)期。例如,沒(méi)有與排他鎖兼容的鎖模式。如果具有排他鎖,則在釋放排他鎖之前,其他事務(wù)均無(wú)法獲取該資源的任何類型(共享、更新或排他)的鎖。另一種情況是,如果共享鎖已應(yīng)用到資源,則即使第一個(gè)事務(wù)尚未完成,其他事務(wù)也可以獲取該項(xiàng)的共享鎖或更新鎖。但是,在釋放共享鎖之前,其他事務(wù)無(wú)法獲取排他鎖。


用戶可以通過(guò)使用SQL SERVER 2005的SQL SERVER PROFILER,指定用來(lái)捕獲有關(guān)跟蹤中鎖事件的信息的鎖事件類別。還可以在系統(tǒng)監(jiān)視器中,從鎖對(duì)象指定計(jì)數(shù)器來(lái)監(jiān)視數(shù)據(jù)庫(kù)引擎實(shí)例中的鎖級(jí)別。


在SQR ?SERVERN ?PROFILER中查看系統(tǒng)鎖定信息時(shí),首先啟動(dòng)SQR ? SERVER ?PROFILER,其窗口如圖12-1所示。


圖12-1 ?SQL Server Profiler ?窗口


選擇系統(tǒng)菜單“文件”—— “新建跟蹤”選項(xiàng),新建一個(gè)跟蹤事件,連接到服務(wù)器,如圖12-2所示。


圖12-2連接服務(wù)器


連接成功,設(shè)置根據(jù)事件屬性。在“跟蹤屬性”對(duì)話框的“常規(guī)”選項(xiàng)卡中,用戶可以設(shè)置跟蹤名稱、使用模板,以及啟用跟蹤停止時(shí)間和將跟蹤存儲(chǔ)到指定文件,如圖12-3所示。


圖12-3 跟蹤屬性 對(duì)話框的常規(guī)選項(xiàng)卡


還可以將跟蹤保存到指定表。在“跟蹤屬性”對(duì)話框的“事件選擇”選項(xiàng)卡中,用戶可以設(shè)置跟蹤的事件以及事件的列,如圖12-4所示。


圖12-4跟蹤屬性對(duì)話框的事件選擇選項(xiàng)卡


設(shè)置完畢,在SQL Server Profiler中顯示跟蹤事件,如圖12-5所示。


圖 12-5 跟蹤事件的顯示


同時(shí),在SSMS的對(duì)象資源管理器中,系統(tǒng)將新建一個(gè)新表,即設(shè)置的保存到表。打開該表,顯示用戶設(shè)置跟蹤的事件以及事件的列。


為了和SQL Server兼容,還可以使用sys.dm_tran_locks動(dòng)態(tài)管理視圖來(lái)替代sp_lock系統(tǒng)存儲(chǔ)過(guò)程。


12.2.4 死鎖及處理
在事務(wù)鎖的使用過(guò)程中,死鎖是一個(gè)不可避免的現(xiàn)象。在下列兩種情況下,可以發(fā)生死鎖。


第一種情況是,當(dāng)兩個(gè)事務(wù)分別鎖定了兩個(gè)單獨(dú)的對(duì)象,這時(shí)每一個(gè)事務(wù)都有要求在另外一個(gè)事務(wù)鎖定的對(duì)象上獲得一個(gè)鎖,因此第一個(gè)事務(wù)都有必須等待另一個(gè)釋放占有的鎖,這時(shí)就發(fā)生了死鎖,這種死鎖是最典型的死鎖形式。


死鎖的第二種情況是,當(dāng)在一個(gè)數(shù)據(jù)庫(kù)中。有若干個(gè)長(zhǎng)時(shí)間運(yùn)行的事務(wù)執(zhí)行并行的操作,當(dāng)查詢分析器處理一種非常復(fù)雜的查詢例如連接查詢時(shí),那么;由于不能控制處理的順序,有可能發(fā)生死鎖現(xiàn)象。


當(dāng)發(fā)生了死鎖現(xiàn)象時(shí), 除非某個(gè)外部進(jìn)程斷開死鎖,否則死鎖中的兩個(gè)事務(wù)都將無(wú)期等待下去。SQL Server 2005的SQL Server Database Engine自動(dòng)檢測(cè)SQL Server中的死鎖循環(huán)。數(shù)據(jù)庫(kù)引擎選擇一個(gè)會(huì)話作為死鎖犧牲,然后終止當(dāng)前事務(wù)(出現(xiàn)錯(cuò)誤)來(lái)打斷死鎖。如果監(jiān)視器檢測(cè)到循環(huán)依賴關(guān)系,通過(guò)自動(dòng)取消其中一個(gè)事務(wù)來(lái)結(jié)束死鎖。處理時(shí)間長(zhǎng)的事務(wù)具有較高的優(yōu)先級(jí),處理時(shí)間較短的事務(wù)具有較低的優(yōu)先級(jí)。在發(fā)生沖突時(shí),保留優(yōu)先級(jí)高的事務(wù),取消優(yōu)先級(jí)的事務(wù)。


用戶可以使用SQL Server Profiler確定死鎖的原因。當(dāng)SQLServer中某組資源的兩個(gè)或多個(gè)線程或進(jìn)程之間存在的依賴關(guān)系時(shí),將會(huì)發(fā)生死鎖。使用SQL Server Profiler,可以創(chuàng)建記錄、重播和顯示死鎖事件的跟蹤以進(jìn)行分析。


若要跟蹤死鎖事件,請(qǐng)將Deadlock graph事件類添加到跟蹤。可以通過(guò)下列任一方法進(jìn)行提取:


在配置跟蹤時(shí),使用“事件提取設(shè)置”選項(xiàng)卡。請(qǐng)注意,只有在“事件選擇“選項(xiàng)卡上選擇了Deadlock graph事件,才會(huì)出現(xiàn)此選項(xiàng)卡。


也可以使用“文件“菜單中的”提取SQL Server事件“選項(xiàng),或者通過(guò)鼠標(biāo)右鍵擊特定事件并選擇”提取事件數(shù)據(jù)“,來(lái)提取并保存各個(gè)事件。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.3 數(shù)據(jù)庫(kù)優(yōu)化
一個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的性能依賴于組成這些系統(tǒng)的數(shù)據(jù)庫(kù)中物理設(shè)計(jì)結(jié)構(gòu)的有效配置。這些物理設(shè)計(jì)結(jié)構(gòu)包括索引、聚集索引、索引視圖和分區(qū)等,其目的在于提高數(shù)據(jù)庫(kù)的性能和可管理性。SQL Server 2005提供了一套綜合的工具,用于優(yōu)化物理數(shù)據(jù)庫(kù)的設(shè)計(jì),其中數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn),是分析一個(gè)或多個(gè)數(shù)據(jù)庫(kù)上工作負(fù)荷(對(duì)要做出化的數(shù)據(jù)庫(kù)招待的一組T-SQL語(yǔ)名句)的性能效果的工具。


本節(jié)主要介紹數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)的使用。


12.3.1 數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)概述
數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)是一種工具,用于分析在一個(gè)或多個(gè)數(shù)據(jù)庫(kù)中運(yùn)行的工作負(fù)荷的性能效果。工作負(fù)荷是對(duì)在優(yōu)化的數(shù)據(jù)庫(kù)招待的一組T-SQL語(yǔ)句。分析數(shù)據(jù)庫(kù)的工作負(fù)荷效果后,數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)會(huì)提供在SQL Server 2005 數(shù)據(jù)庫(kù)中添加、刪除或修改物理設(shè)計(jì)結(jié)構(gòu)的建議。這些物理性能結(jié)構(gòu)包括聚集索引、非聚集索引、索引視圖和分區(qū)。實(shí)現(xiàn)這些結(jié)構(gòu)之后,數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)使查詢處理器能夠用最短的時(shí)間性執(zhí)行工作負(fù)荷任務(wù)。


12.3.2 數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)的使用
數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)提供了兩種使用方式:


圖形界面。用于優(yōu)化數(shù)據(jù)庫(kù)、查看優(yōu)化建議和報(bào)告的工具。


命令行實(shí)用工具程序dta.exe。用于實(shí)現(xiàn)數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)在軟件程序和腳本方面的功能。


本節(jié)只介紹圖形界面優(yōu)化數(shù)據(jù)庫(kù),需要啟動(dòng)數(shù)據(jù)庫(kù)引擎優(yōu)化顧問(wèn)。首先連接到服務(wù)器,如圖12-6所示。


圖12-6連接服務(wù)器


連接成功后,進(jìn)入數(shù)據(jù)庫(kù)引擎優(yōu)顧問(wèn)。如圖12-7所示。


圖12-7數(shù)據(jù)庫(kù)引擎優(yōu)顧問(wèn)


用戶可以在“會(huì)話框”中設(shè)置數(shù)據(jù)庫(kù)優(yōu)化設(shè)置。選擇工作負(fù)荷文件,即由SQL Server Proriler創(chuàng)建的事件文件。選擇需要優(yōu)化的數(shù)據(jù)庫(kù)。如圖12-8所示。


圖12-8選擇需要優(yōu)化的數(shù)據(jù)庫(kù)


選擇系統(tǒng)菜單“操作”→“開始分析”選項(xiàng),系統(tǒng)自動(dòng)對(duì)數(shù)據(jù)庫(kù)進(jìn)行優(yōu)化分析操作。優(yōu)化分析結(jié)束,在“會(huì)話框”中多出了3個(gè)選項(xiàng):進(jìn)度、建議、和報(bào)告。顯示優(yōu)化分析的進(jìn)度信息,建議信息和優(yōu)化報(bào)告信息。


用戶還可以選擇系統(tǒng)菜單“文件”→“新建會(huì)話”選項(xiàng),新建一個(gè)會(huì)話,優(yōu)化其他的數(shù)據(jù)庫(kù)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 12.4 小結(jié)
結(jié)合第1章DBMS的DCL數(shù)據(jù)庫(kù)的安全性控制功能,本章講解事物的基本概念和SQL Server 2005事物處理和并發(fā)控制的基本概念,包括封鎖、封鎖協(xié)議、活鎖、死鎖等概念;講解SQL Server 2005的并發(fā)控制機(jī)制。
========

數(shù)據(jù)庫(kù) 并發(fā)控制 常見(jiàn)鎖



封鎖 (數(shù)據(jù)庫(kù))
封鎖是一項(xiàng)用于多用戶同時(shí)訪問(wèn)數(shù)據(jù)庫(kù)的技術(shù),是實(shí)現(xiàn)并發(fā)控制的一項(xiàng)重要手段,能夠防止當(dāng)多用戶改寫數(shù)據(jù)庫(kù)時(shí)造成數(shù)據(jù)丟失和損壞。當(dāng)有一個(gè)用戶對(duì)數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù)進(jìn)行操作時(shí),在讀取數(shù)據(jù)前先鎖住數(shù)據(jù),這樣其他用戶就無(wú)法訪問(wèn)和修改該數(shù)據(jù),直到這一數(shù)據(jù)修改并寫回?cái)?shù)據(jù)庫(kù)解除封鎖為止。


樂(lè)觀并發(fā)控制(樂(lè)觀鎖)
在關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)里,樂(lè)觀并發(fā)控制(又名“樂(lè)觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種并發(fā)控制的方法。它假設(shè)多用戶并發(fā)的事務(wù)在處理時(shí)不會(huì)彼此互相影響,各事務(wù)能夠在不產(chǎn)生鎖的情況下處理各自影響的那部分?jǐn)?shù)據(jù)。在提交數(shù)據(jù)更新之前,每個(gè)事務(wù)會(huì)先檢查在該事務(wù)讀取數(shù)據(jù)后,有沒(méi)有其他事務(wù)又修改了該數(shù)據(jù)。如果其他事務(wù)有更新的話,正在提交的事務(wù)會(huì)進(jìn)行回滾。樂(lè)觀事務(wù)控制最早是由孔祥重(H.T.Kung)教授提出[1]。


樂(lè)觀并發(fā)控制多數(shù)用于數(shù)據(jù)爭(zhēng)用不大、沖突較少的環(huán)境中,這種環(huán)境中,偶爾回滾事務(wù)的成本會(huì)低于讀取數(shù)據(jù)時(shí)鎖定數(shù)據(jù)的成本,因此可以獲得比其他并發(fā)控制方法更高的吞吐量。


目錄
1 樂(lè)觀并發(fā)控制的階段
2 優(yōu)點(diǎn)與不足
3 相關(guān)條目
4 參考文獻(xiàn)
5 外部鏈接
樂(lè)觀并發(fā)控制的階段
樂(lè)觀并發(fā)控制的事務(wù)包括以下階段:[來(lái)源請(qǐng)求]


讀取:事務(wù)將數(shù)據(jù)讀入緩存,這時(shí)系統(tǒng)會(huì)給事務(wù)分派一個(gè)時(shí)間戳。
校驗(yàn):事務(wù)執(zhí)行完畢后,進(jìn)行提交。這時(shí)同步校驗(yàn)所有事務(wù),如果事務(wù)所讀取的數(shù)據(jù)在讀取之后又被其他事務(wù)修改,則產(chǎn)生沖突,事務(wù)被中斷回滾。
寫入:通過(guò)校驗(yàn)階段后,將更新的數(shù)據(jù)寫入數(shù)據(jù)庫(kù)。


悲觀并發(fā)控制(悲觀鎖)
在關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)里,悲觀并發(fā)控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種并發(fā)控制的方法。它可以阻止一個(gè)事務(wù)以影響其他用戶的方式來(lái)修改數(shù)據(jù)。如果一個(gè)事務(wù)執(zhí)行的操作都某行數(shù)據(jù)應(yīng)用了鎖,那只有當(dāng)這個(gè)事務(wù)把鎖釋放,其他事務(wù)才能夠執(zhí)行與該鎖沖突的操作。


悲觀并發(fā)控制主要用于數(shù)據(jù)爭(zhēng)用激烈的環(huán)境,以及發(fā)生并發(fā)沖突時(shí)使用鎖保護(hù)數(shù)據(jù)的成本要低于回滾事務(wù)的成本的環(huán)境中。
========

多種數(shù)據(jù)庫(kù)的并發(fā)控制比較



多種數(shù)據(jù)庫(kù)的并發(fā)控制比較
內(nèi)容:
比較的ORACLE INFORMIX DB2 SYBASE MSSQL等的并發(fā)控制機(jī)制。比較分析悲觀與樂(lè)觀并發(fā)控制機(jī)制的異同。
引言:
l ? ? ? 在關(guān)系數(shù)據(jù)庫(kù)(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢復(fù)和交易單位為一個(gè)事務(wù)(Transactions),事務(wù)具有ACID(原子性,一致性,隔離性和永久性)特征。關(guān)系數(shù)據(jù)庫(kù)為了確保并發(fā)用戶在存取同一數(shù)據(jù)庫(kù)對(duì)象時(shí)的正確性(即無(wú)丟失更新、可重復(fù)讀、不讀"臟"數(shù)據(jù),無(wú)"幻像"讀),數(shù)據(jù)庫(kù)中引入了并發(fā)(鎖)機(jī)制。基本的鎖類型有兩種:排它鎖(Exclusive locks記為X鎖)和共享鎖(Share locks記為S鎖)。
l ? ? ? 排它鎖:若事務(wù)T對(duì)數(shù)據(jù)D加X(jué)鎖,則其它任何事務(wù)都不能再對(duì)D加任何類型的鎖,直至T釋放D上的X鎖;一般要求在修改數(shù)據(jù)前要向該數(shù)據(jù)加排它鎖,所以排它鎖又稱為寫鎖。
l ? ? ? 共享鎖:若事務(wù)T對(duì)數(shù)據(jù)D加S鎖,則其它事務(wù)只能對(duì)D加S鎖,而不能加X(jué)鎖,直至T釋放D上的S鎖;一般要求在讀取數(shù)據(jù)前要向該數(shù)據(jù)加共享鎖,所以共享鎖又稱為讀鎖。


相關(guān)解釋
l頁(yè):以磁盤頁(yè)面(disk pages)為單位存儲(chǔ)數(shù)據(jù)。一個(gè)磁盤頁(yè)面包含一個(gè)或多個(gè)記錄。
l鍵字級(jí):Informix(在一定情況下,數(shù)據(jù)庫(kù)服務(wù)器需要鎖一個(gè)不存在的記錄。它的效果相當(dāng)于在記錄將要存在的地方放一個(gè)鎖。當(dāng)表使用記錄鎖時(shí),對(duì)假想的記錄使用鍵字鎖。當(dāng)表使用頁(yè)級(jí)鎖時(shí),含有或可能含有鍵字的索引頁(yè)將被設(shè)置鍵級(jí)鎖)。MSSQL(索引中的行鎖。用于保護(hù)可串行事務(wù)中的鍵范圍)。
l擴(kuò)展盤區(qū):相鄰的八個(gè)數(shù)據(jù)頁(yè)或索引頁(yè)構(gòu)成的一組。
l表空間:DB2 的表空間按管理方式分為兩種:系統(tǒng)管理空間和數(shù)據(jù)庫(kù)管理空間。 按類型分為:規(guī)則表空間、長(zhǎng)整數(shù)表空間、系統(tǒng)臨時(shí)表空間、用戶臨時(shí)表空間 。其中長(zhǎng)整數(shù)表空間只能是DMS的。規(guī)則表空間中包含用戶數(shù)據(jù)的表。默認(rèn)用戶表空間名為USERSPACE1,索引也存在規(guī)則表空間中,另外系統(tǒng)目錄表也放在規(guī)則表空間中。
?
DB2數(shù)據(jù)庫(kù)表鎖的模式?


幾種表鎖的模式進(jìn)一步闡述:
lIS、IX、SIX方式用于表一級(jí)并需要行鎖配合,他們可以阻止其他應(yīng)用程序?qū)υ摫砑由吓潘i。
l如果一個(gè)應(yīng)用程序獲得某表的IS鎖,該應(yīng)用程序可獲得某一行上的S鎖,用于只讀操作,同時(shí)其他應(yīng)用程序也可以讀取該行,或是對(duì)表中的其他行進(jìn)行更改。
l如果一個(gè)應(yīng)用程序獲得某表的IX鎖,該應(yīng)用程序可獲得某一行上的X鎖,用于更改操作,同時(shí)其他應(yīng)用程序可以讀取或更改表中的其他行。
l如果一個(gè)應(yīng)用程序獲得某表的SIX鎖,該應(yīng)用程序可以獲得某一行上的X鎖,用于更改操作,同時(shí)其他應(yīng)用程序只能對(duì)表中其他行進(jìn)行只讀操作。
幾種表鎖的模式進(jìn)一步闡述:
lS、U、X和Z方式用于表一級(jí),但并不需要行鎖配合,是比較嚴(yán)格的表加鎖策略。
l如果一個(gè)應(yīng)用程序得到某表的S鎖。該應(yīng)用程序可以讀表中的任何數(shù)據(jù)。同時(shí)它允許其他應(yīng)用程序獲得該表上的只讀請(qǐng)求鎖。如果有應(yīng)用程序需要更改讀該表上的數(shù)據(jù),必須等S鎖被釋放。
l如果一個(gè)應(yīng)用程序得到某表的U鎖,該應(yīng)用程序可以讀表中的任何數(shù)據(jù),并最終可以通過(guò)獲得表上的X鎖來(lái)得到對(duì)表中任何數(shù)據(jù)的修改權(quán)。其他應(yīng)用程序只能讀取該表中的數(shù)據(jù)。U鎖與S鎖的區(qū)別主要在于更改的意圖上。U鎖的設(shè)計(jì)主要是為了避免兩個(gè)應(yīng)用程序在擁有S鎖的情況下同時(shí)申請(qǐng)X鎖而造成死鎖的。
l如果一個(gè)應(yīng)用程序得到某表上的X鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序不能對(duì)該表進(jìn)行讀或者更改操作。
l如果一個(gè)應(yīng)用程序得到某表上的Z鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序,包括未提交讀程序都不能對(duì)該表進(jìn)行讀或者更改操作。
lIN鎖用于表上以允許未提交讀這一概念。
DB2數(shù)據(jù)庫(kù)行鎖的模式
?
DB2數(shù)據(jù)庫(kù)表鎖的相容矩陣
?
DB2數(shù)據(jù)庫(kù)行鎖的相容矩陣
?
DB2中各SQL語(yǔ)句產(chǎn)生表鎖的情況(假設(shè)缺省的隔離級(jí)別為CS):


?
DB2鎖的升級(jí) (1)


l每個(gè)鎖在內(nèi)存中都需要一定的內(nèi)存空間,為了減少鎖需要的內(nèi)存開銷,DB2提供了鎖升級(jí)的功能。鎖升級(jí)是通過(guò)對(duì)表加上非意圖性的表鎖,同時(shí)釋放行鎖來(lái)減少鎖的數(shù)目,從而達(dá)到減少鎖需要的內(nèi)存開銷的目的。鎖升級(jí)是由數(shù)據(jù)庫(kù)管理器自動(dòng)完成的,有兩個(gè)數(shù)據(jù)庫(kù)的配置參數(shù)直接影響鎖升級(jí)的處理:
llocklist--在一個(gè)數(shù)據(jù)庫(kù)全局內(nèi)存中用于鎖存儲(chǔ)的內(nèi)存。單位為頁(yè)(4K)。
lmaxlocks--一個(gè)應(yīng)用程序允許得到的鎖占用的內(nèi)存所占locklist大小的百分比。
l鎖升級(jí)會(huì)在這兩種情況下被觸發(fā):
l某個(gè)應(yīng)用程序請(qǐng)求的鎖所占用的內(nèi)存空間超出了maxlocks與locklist的乘積大小。這時(shí),數(shù)據(jù)庫(kù)管理器將試圖通過(guò)為提出鎖請(qǐng)求的應(yīng)用程序申請(qǐng)表鎖,并釋放行鎖來(lái)節(jié)省空間。
DB2鎖的升級(jí) (2)


l在一個(gè)數(shù)據(jù)庫(kù)中已被加上的全部鎖所占的內(nèi)存空間超出了locklist定義的大小。這時(shí),數(shù)據(jù)庫(kù)管理器也將試圖通過(guò)為提出鎖請(qǐng)求的應(yīng)用程序申請(qǐng)表鎖,并釋放行鎖來(lái)節(jié)省空間。
l鎖升級(jí)雖然會(huì)降低OLTP應(yīng)用程序的并發(fā)性能,但是鎖升級(jí)后會(huì)釋放鎖占有內(nèi)存并增大可用的鎖的內(nèi)存空間。
l鎖升級(jí)是有可能會(huì)失敗的,比如,現(xiàn)在一個(gè)應(yīng)用程序已經(jīng)在一個(gè)表上加有IX鎖,表中的某些行上加有X鎖,另一個(gè)應(yīng)用程序又來(lái)請(qǐng)求表上的IS鎖,以及很多行上的S鎖,由于申請(qǐng)的鎖數(shù)目過(guò)多引起鎖的升級(jí)。數(shù)據(jù)庫(kù)管理器試圖為該應(yīng)用程序申請(qǐng)表上的S鎖來(lái)減少所需要的鎖的數(shù)目,但S鎖與表上原有的IX鎖沖突,鎖升級(jí)不能成功。
l如果鎖升級(jí)失敗,引起鎖升級(jí)的應(yīng)用程序?qū)⒔拥揭粋€(gè)-912的SQLCODE。在鎖升級(jí)失敗后,DBA應(yīng)該考慮增加locklist的大小或者增大maxlocks的百分比。同時(shí)對(duì)編程人員來(lái)說(shuō)可以在程序里對(duì)發(fā)生鎖升級(jí)后程序回滾后重新提交事務(wù)(例如:if sqlca.sqlcode=-912 then rollback and retry等)。
?
Oracle 多粒度鎖機(jī)制介紹


l根據(jù)保護(hù)對(duì)象的不同,Oracle數(shù)據(jù)庫(kù)鎖可以分為以下幾大類:
l(1) DML lock(data locks,數(shù)據(jù)鎖):用于保護(hù)數(shù)據(jù)的完整性;
l(2) DDL lock(dictionary locks,字典鎖):用于保護(hù)數(shù)據(jù)庫(kù)對(duì)象的結(jié)構(gòu)(例如表、視圖、索引的結(jié)構(gòu)定義);
l(3) Internal locks 和latches(內(nèi)部鎖與閂):保護(hù)內(nèi)部數(shù)據(jù)庫(kù)結(jié)構(gòu);
l(4) Distributed locks(分布式鎖):用于OPS(并行服務(wù)器)中;
l(5) PCM locks(并行高速緩存管理鎖):用于OPS(并行服務(wù)器)中。
l在Oracle中最主要的鎖是DML(也可稱為data locks,數(shù)據(jù)鎖)鎖。從封鎖粒度(封鎖對(duì)象的大小)的角度看,Oracle DML鎖共有兩個(gè)層次,即行級(jí)鎖和表級(jí)鎖。
?
Oracle的TX鎖行級(jí)鎖、事務(wù)鎖?


l許多對(duì)Oracle不太了解的技術(shù)人員可能會(huì)以為每一個(gè)TX鎖代表一條被封鎖的數(shù)據(jù)行,其實(shí)不然。TX的本義是Transaction(事務(wù))當(dāng)一個(gè)事務(wù)第一次執(zhí)行數(shù)據(jù)更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE語(yǔ)句進(jìn)行查詢時(shí),它即獲得一個(gè)TX(事務(wù))鎖,直至該事務(wù)結(jié)束(執(zhí)行COMMIT或ROLLBACK操作)時(shí),該鎖才被釋放。所以,一個(gè)TX鎖,可以對(duì)應(yīng)多個(gè)被該事務(wù)鎖定的數(shù)據(jù)行(在我們用的時(shí)候多是啟動(dòng)一個(gè)事務(wù),然后SELECT… FOR UPDATE NOWAIT)。
l在Oracle的每行數(shù)據(jù)上,都有一個(gè)標(biāo)志位來(lái)表示該行數(shù)據(jù)是否被鎖定。Oracle不像DB2那樣,建立一個(gè)鏈表來(lái)維護(hù)每一行被加鎖的數(shù)據(jù),這樣就大大減小了行級(jí)鎖的維護(hù)開銷,也在很大程度上避免了類似DB2使用行級(jí)鎖時(shí)經(jīng)常發(fā)生的鎖數(shù)量不夠而進(jìn)行鎖升級(jí)的情況。數(shù)據(jù)行上的鎖標(biāo)志一旦被置位,就表明該行數(shù)據(jù)被加X(jué)鎖,Oracle在數(shù)據(jù)行上沒(méi)有S鎖。
Oracle意向鎖?


l意向鎖的含義是如果對(duì)一個(gè)結(jié)點(diǎn)加意向鎖,則說(shuō)明該結(jié)點(diǎn)的下層結(jié)點(diǎn)正在被加鎖;對(duì)任一結(jié)點(diǎn)加鎖時(shí),必須先對(duì)它的上層結(jié)點(diǎn)加意向鎖。如:對(duì)表中的任一行加鎖時(shí),必須先對(duì)它所在的表加意向鎖,然后再對(duì)該行加鎖。這樣一來(lái),事務(wù)對(duì)表加鎖時(shí),就不再需要檢查表中每行記錄的鎖標(biāo)志位了,系統(tǒng)效率得以大大提高。
l由兩種基本的鎖類型(S鎖、X鎖),可以自然地派生出兩種意向鎖:
l另外,基本的鎖類型(S、X)與意向鎖類型(IS、IX)之間還可以組合出新的鎖類型,理論上可以組合出4種,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不難看出,實(shí)際上只有S+IX有新的意義,其它三種組合都沒(méi)有使鎖的強(qiáng)度得到提高(即:S+IS=S,X+IS=X,X+IX=X,這里的"="指鎖的強(qiáng)度相同)。所謂鎖的強(qiáng)度是指對(duì)其它鎖的排斥程度。
l這樣我們又可以引入一種新的鎖的類型:共享意向排它鎖(Shared Intent Exclusive Lock,簡(jiǎn)稱SIX鎖):如果對(duì)一個(gè)數(shù)據(jù)庫(kù)對(duì)象加SIX鎖,表示對(duì)它加S鎖,再加IX鎖,即SIX=S+IX。例如:事務(wù)對(duì)某個(gè)表加SIX鎖,則表示該事務(wù)要讀整個(gè)表(所以要對(duì)該表加S鎖),同時(shí)會(huì)更新個(gè)別行(所以要對(duì)該表加IX鎖)。
l具有意向鎖的多粒度封鎖方法中任意事務(wù)T要對(duì)一個(gè)數(shù)據(jù)庫(kù)對(duì)象加鎖,必須先對(duì)它的上層結(jié)點(diǎn)加意向鎖。申請(qǐng)封鎖時(shí)應(yīng)按自上而下的次序進(jìn)行;釋放封鎖時(shí)則應(yīng)按自下而上的次序進(jìn)行;具有意向鎖的多粒度封鎖方法提高了系統(tǒng)的并發(fā)度,減少了加鎖和解鎖的開銷。
Oracle的TM鎖(表級(jí)鎖)?
? ??
Oracle數(shù)據(jù)庫(kù)TM鎖小結(jié)
?
多粒度封鎖機(jī)制的監(jiān)控?


l快照監(jiān)控
l事件監(jiān)控方式
l視圖(Oracle)
v$lock視圖列出當(dāng)前系統(tǒng)持有的或正在申請(qǐng)的所有鎖的情況
?
v$locked_object視圖列出當(dāng)前系統(tǒng)中哪些對(duì)象正被鎖定
?
總結(jié) (1)
l1.Oracle通過(guò)具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個(gè)層次(粒度):即表級(jí)和行級(jí)。通常的DML操作在表級(jí)獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級(jí);DB2也是通過(guò)具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個(gè)層次(粒度):即表級(jí)和行級(jí)。通常的DML操作在表級(jí)獲得的只是意向鎖(IS,SIX或IX),其真正的封鎖粒度也是在行級(jí);另外,在Oracle數(shù)據(jù)庫(kù)中,單純地讀數(shù)據(jù)(SELECT)并不加鎖,這些都提高了系統(tǒng)的并發(fā)程度,Oracle強(qiáng)調(diào)的是能夠"讀"到數(shù)據(jù),并且能夠快速的進(jìn)行數(shù)據(jù)讀取。而DB2的鎖強(qiáng)調(diào)的是"讀一致性",進(jìn)行讀數(shù)據(jù)(SELECT)時(shí)會(huì)根據(jù)不同的隔離級(jí)別(RR,RS,CS)而分別加S,IS,IS鎖,只有在使用UR隔離級(jí)別時(shí)才不加鎖。從而保證不同應(yīng)用程序和用戶讀取的數(shù)據(jù)是一致的。
總結(jié)(2)
l2. 在支持高并發(fā)度的同時(shí),DB2和Oracle對(duì)鎖的操縱機(jī)制有所不同:Oracle利用意向鎖及數(shù)據(jù)行上加鎖標(biāo)志位等設(shè)計(jì)技巧,減小了Oracle維護(hù)行級(jí)鎖的開銷,使其在數(shù)據(jù)庫(kù)并發(fā)控制方面有著一定的優(yōu)勢(shì)。而DB2中對(duì)每個(gè)鎖會(huì)在鎖的內(nèi)存(locklist)中申請(qǐng)分配一定字節(jié)的內(nèi)存空間,具體是X鎖64字節(jié)內(nèi)存,S鎖32字節(jié)內(nèi)存(注:DB2 V8之前是X鎖72字節(jié)內(nèi)存而S鎖36字節(jié)內(nèi)存)。
l3. Oracle數(shù)據(jù)庫(kù)中不存在鎖升級(jí),而DB2數(shù)據(jù)庫(kù)中當(dāng)數(shù)據(jù)庫(kù)表中行級(jí)鎖的使用超過(guò)locklist*maxlocks會(huì)發(fā)生鎖升級(jí)。
l4. 在Oracle中當(dāng)一個(gè)session對(duì)表進(jìn)行insert,update,delete時(shí)候,另外一個(gè)session仍然可以從Orace回滾段或者還原表空間中讀取該表的前映象(before image); 而在DB2中當(dāng)一個(gè)session對(duì)表進(jìn)行insert,update,delete時(shí)候,另外一個(gè)session仍然在讀取該表數(shù)據(jù)時(shí)候會(huì)處于lock wait狀態(tài),除非使用UR隔離級(jí)別可以讀取第一個(gè)session的未提交的值;所以O(shè)racle同一時(shí)刻不同的session有讀不一致的現(xiàn)象,而DB2在同一時(shí)刻所有的session都是"讀一致"的。
?
SQLServer使用以下資源鎖模式
?
l共享 (S):用于不更改或不更新數(shù)據(jù)的操作(只讀操作),如 SELECT 語(yǔ)句。
l更新 (U): ? 用于可更新的資源中。防止當(dāng)多個(gè)會(huì)話在讀取、鎖定以及隨后可能進(jìn)行的資源更新時(shí)發(fā)生常見(jiàn)形式的死鎖。
l排它 (X): ? 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會(huì)同時(shí)對(duì)同一資源進(jìn)行多重更新。
l意向:用于建立鎖的層次結(jié)構(gòu)。意向鎖的類型為:意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。
l架構(gòu):在執(zhí)行依賴于表架構(gòu)的操作時(shí)使用。架構(gòu)鎖的類型為:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。
l大容量更新 (BU):向表中大容量復(fù)制數(shù)據(jù)并指定了 TABLOCK 提示時(shí)使用。
架構(gòu)鎖
?
l執(zhí)行表的數(shù)據(jù)定義語(yǔ)言 (DDL) 操作(例如添加列或除去表)時(shí)使用架構(gòu)修改 (Sch-M) 鎖。
l當(dāng)編譯查詢時(shí),使用架構(gòu)穩(wěn)定性 (Sch-S) 鎖。架構(gòu)穩(wěn)定性 (Sch-S) 鎖不阻塞任何事務(wù)鎖,包括排它 (X) 鎖。因此在編譯查詢時(shí),其它事務(wù)(包括在表上有排它 (X) 鎖的事務(wù))都能繼續(xù)運(yùn)行。但不能在表上執(zhí)行 DDL 操作。
大容量更新鎖
l當(dāng)將數(shù)據(jù)大容量復(fù)制到表,且指定了 TABLOCK 提示或者使用 sp_tableoption 設(shè)置了 table lock on bulk 表選項(xiàng)時(shí),將使用大容量更新 (BU) 鎖。大容量更新 (BU) 鎖允許進(jìn)程將數(shù)據(jù)并發(fā)地大容量復(fù)制到同一表,同時(shí)防止其它不進(jìn)行大容量復(fù)制數(shù)據(jù)的進(jìn)程訪問(wèn)該表。
?
Sybase鎖的狀態(tài)


lSQL SERVER加鎖有三種狀態(tài):
l1)意向鎖(intend)—是一種表級(jí)鎖,它表示在一個(gè)數(shù)據(jù)頁(yè)上獲得一個(gè)S或X鎖的意向。意向鎖可以防止其他事務(wù)在該數(shù)據(jù)頁(yè)的表上獲得排它鎖。
l2)阻塞(blocking,簡(jiǎn)記blk)—它表明目前加鎖進(jìn)程的狀態(tài),帶有blk后綴的鎖說(shuō)明該進(jìn)程目前正阻塞另一個(gè)需要獲得鎖的進(jìn)程,只有這一進(jìn)程完成,其他進(jìn)程才可以進(jìn)行。
l3)需求鎖(demand)—表示此時(shí)該進(jìn)程企圖得到一個(gè)排它鎖。它可以防止在這一表或頁(yè)上加過(guò)多的S鎖,她表示某一事務(wù)是下一個(gè)去鎖定該表和該頁(yè)的事務(wù)。
l需求鎖是一個(gè)內(nèi)部過(guò)程,因此用sp_lock是無(wú)法看見(jiàn)的。
?
Informix
l鎖的類型 INFORMIX有三種不同類型的鎖。它們?cè)诓煌那闆r下使用。?
1. SHARED鎖?
SHARED鎖只保留對(duì)象的可讀性。當(dāng)鎖存在時(shí),對(duì)象不能改變。多個(gè)程序可對(duì)同個(gè)對(duì)象加SHARED鎖。?
2. EXCLUSIVE鎖?
只能使單個(gè)程序使用。在程序要改變對(duì)象時(shí)使用。當(dāng)其他鎖存在時(shí),EXCLUSIVE鎖不能使用。當(dāng)使用了EXCLUSIVE 鎖后,其他鎖不能用于同一對(duì)象。?
3. PROMOTABLE鎖?
實(shí)現(xiàn)更新的目的。PROMOTABLE鎖可以放在已經(jīng)有SHARED鎖的記錄,但不能放在已經(jīng)有PROMOTABLE鎖和EXCLUSIVE 鎖的地方。當(dāng)記錄上無(wú)其他鎖(含SHARED 鎖)情況下,這時(shí)在程序準(zhǔn)備改變鎖的記錄時(shí),PROMOTABLE鎖可以提升為EXCLUSIVE鎖。如果在已有SHARED鎖的記錄上設(shè)置了PROMOTABLE鎖,在PROMOTABLE鎖可以提升到EXCLUSIVE鎖?
之前需要?jiǎng)h除SHARED 鎖。PROMOTABLE鎖只能在INFORMIX Universal Server中支持。?
========

相關(guān)鏈接

http://blog.csdn.net/xiangminjing/article/details/5922325
http://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

總結(jié)

以上是生活随笔為你收集整理的数据库并发学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。