數據庫原理及應用-數據庫管理系統 DBMS
2018-02-20 14:35:34
數據庫管理系統(英語:database management system,縮寫:DBMS) 是一種針對對象數據庫,為管理數據庫而設計的大型電腦軟件管理系統。具有代表性的數據管理系統有:Oracle、Microsoft SQL Server、Access、MySQL及PostgreSQL等。
一、DBMS內核
Parser:編譯器,或者說是語法分析器
Grant checking:授權檢查器,用來檢查特定用戶的權限問題
Semantic analysis and query treatment ( DDL QL DML DCL ):語義分析和查詢處理,核心中的核心,SQL語句的功能實現
Access management:訪問管理,將表和文件進行映射
Concurrency control:並發控制
Recovery mechanism:恢復機制
二、DBMS的進程結構
1、單進程結構,Single process structure
2、多進程結構,Multi processes structure
一個應用進程對應一個DBMS核心進程,每當一個應用進程需要訪問數據庫的時候,就會發起一個連接請求,系統就會生成一個DBMS核心進程,並創建管道進行交互。
3、多線程結構,Multi threads structure
在操作系統中創建進程需要消耗大量的系統資源,如果使用多進程結構,每次對新的應用程序都創建一個新的DBMS核心進程,那麽操作系統的資源將會很快耗盡。這裏,可以使用多線程結構來進行優化。線程可以看成一個輕量級的進程,一個進程裏可以包含多個線程,每個線程消耗的系統資源要比進程少很多。
同一個進程中的多個線程共享進程的數據,在DBMS核心進程中有如下的共享內容:
DAEMON:用來監聽來自應用程序的請求,對每個新的應用程序的連接請求建立一個線程;
catalog:目錄,記錄數據庫中表的信息;
lock table:鎖表,在並發控制的時候發揮作用;
buffer:緩沖區;
三、Database Access Management
數據庫訪問管理所要做的是將對數據庫的訪問轉換成操作系統中的文件對象的訪問。數據庫訪問管理,也就是物理層上的文件結構定義和文件的存取路徑將會直接影響數據庫的查詢速度。沒有一種文件結構是可以一勞永逸的,所以我們需要考慮一下幾個問題:
- 訪問類型;
- 文件結構;
- 索引技術;
- 訪問原語;
1)訪問類型,Access Types
Query all or most records of a file (>15%):查詢的元組數量占文件的15%以上,我們就認為是這種類型,一般這種大量查詢可以使用堆文件進行存儲;
Query some special record
Query some records (<15%)
Scope query:範圍查詢
Update
2)文件存儲結構,File Organization
堆文件:順序掃描進行查詢,適合查詢超過15%的查詢操作
Hash文件:查詢效率高,適合查詢特殊查詢操作
索引文件:堆文件 and B+樹索引,適用面最廣,也最常用
動態Hash:映射空間隨著數據量的大小進行改變
Raw disk:註意文件的邏輯順序和物理順序是兩個概念,一般來說,物理順序是由操作系統控制的。使用Raw disk可以自己確定文件在磁盤的存儲位置,一次申請連續存儲空間,按屬性值連續存儲,也被稱為Clustering index,簇集索引。
3)索引技術
四、查詢優化
關系型數據庫在剛提出的時候是遭到反對的,因為使用關系型數據庫在查詢的時候效率很低,比如一個10000條元組的表和50000條元組的表進行連接,那麽就會產生5億條元組,這是不可接受的。但是,為什麽現在關系型數據庫成為了主流呢?因為其查詢優化技術有了長足的發展。
查詢優化會將用戶的SQL語言進行重寫,生成效率更高的查詢語言進行查詢,其根本目標就是使用盡量少的資源,盡量快的將查詢結果返回給用戶。
可以分為兩步優化:Algebra Optimization(代數優化,就是重寫);Operation Optimization(操作優化)
舉個例子:計算x^2 + 2xy + y^2,可以先進行代數優化將之轉換成等價的(x+y)^2,所謂操作優化就是選擇合適的加法和乘法實現方式。
- Algebra Optimization
代數優化的基本目標是對用戶的查詢操作進行改寫,將之生成更優的形式。基本原則是將一元操作盡可能的向下壓;尋找合並公共子表達式。
- Operation Optimization
操作優化的目標是將每個操作如投影,連接操作等如何選擇更好的算法進行實現。下面以連接運算為例。
連接操作的方法一:嵌套循環,算法復雜度為O(nm)。
連接操作的方法二:歸並掃描,前提按照連接屬性的值進行了外排序。
連接操作的方法三:基於B+索引的循環,通過B+樹進行查找,而不用單純遍歷。
四、恢復機制
數據庫的恢復機制指:預防數據庫出現差錯;發生故障後,可以進行恢復,將數據庫變為穩定的狀態。
恢復機制有兩個基本的原則:冗余是必須的,也就是要進行必要的備份工作;能夠預測所有的可能故障情況。
恢復機制的實現方法:
1) Periodical dumping
Periodical dumping:每隔一段時間將整個數據庫備份一次。
這種方法有一個缺點就是完整備份數據庫不可能經常進行,這樣在兩次備份中出現差錯會導致中間很多的更新操作的丟失。
解決方法很簡單,就是在間斷性備份的基礎上加上增量備份 Backup + Incremental dumping。由於增量的數據量較少,可以較多次的進行備份操作。雖然依然存在丟失更新,但是由於間隔短,所以丟失的內容較少。早期使用,適合小型的數據庫。
2)Backup + Log
備份加日誌,所謂日誌,其實就是流水帳,記錄備份一來,用戶對數據庫做的所有改變。不會產生丟失更新的問題。
五、事務處理機制
對數據庫的操作是以事務為單位進行運行的,如果沒有顯示的指明Transaction,則默認每條SQL為一個事務。
一個事務(Transaction)就是一組SQL語句,具有如下特性ACID:
- 原子性(Atomic):要麽全部執行,要麽都不執行;
-
一致性(Consistent):事務在完成時,必須使所有的數據都保持一致狀態。在相關數據庫中,所有規則都必須應用於事務的修改,以保持所有數據的完整性。事務結束時,所有的內部數據結構(如 B 樹索引或雙向鏈表)都必須是正確的;
-
隔離性(Insulation):同時運行的事務不能相互幹擾;
- 持久性(Duration):一個事務只要完成,那麽這個操作將永久反映在數據庫上。
六、並發控制
並發是指在多用戶數據庫管理系統裏,允許多個事務同時對數據庫進行訪問。
支持並發的好處:提高系統的利用率和減少響應時間;由於事務很有可能訪問數據庫的不同內容,所以並發會極大的提高效率。
1)並發中可能會出現的三種沖突
- write – write:寫寫沖突,會造成丟失更新的問題。寫寫沖突是必須避免的。
- write – read:寫讀沖突,會造成數據的臟讀的問題。
- read – write:讀寫沖突,會造成數據的重復讀沖突的問題。
2)可串行化理論
可串行化理論是用來判別並行運算的結果是否正確的依據。並發控制的目標就是並發結果是可串行化的。
可串行化是指 {T 1 ,T 2 ,…T n }這n個事務的並發結果如果和其串行運行結果的其中一個相等(n!中的任意一個),那麽我們就認為,這次的並發執行的結果是正確的。
3)封鎖法
加鎖機制是最常見的並發控制策略,其核心思想就是:在並發的事務對數據庫中數據進行訪問的時候需要提前加鎖,如果是沒有沖突的話,那麽各自鎖上自己占用的資源,如果產生了沖突,那麽就按照先搶到鎖的先運行的方法來執行,其實就是一種通過鎖機制強行串行化的方法,從而保證並發結果是可串行化的。
(a)X locks
系統中只有一種鎖,就是排他鎖,事務對數據的讀或寫都要申請排他鎖。
定理:並行調度是Well-formed + 2PL,則可證明其並行結果是可串行化的。
(well-formed:每個事務都很守規矩,即每次讀寫數據前都會先申請鎖)
(2PL:事務在讀寫數據前會先統一進行申請鎖,最後再統一釋放鎖,也就是說在釋放鎖資源後不再繼續申請鎖)
(b)(S,X) locks
我們知道,多個事務同時讀一個數據是沒有沖突的,所以如果只是單純的排他鎖的話,系統的效率就會很低。為了進一步提高效率,提出了(S,X) locks。
S locks:讀操作申請
X locks:寫操作申請
(c)(S,U,X) locks
我們知道,在更新操作的時候,很多情況下是先把數據讀取出來再對對其修改,最後寫回。我們可以在寫回前定義一個U鎖,在寫回的時候再升級成X鎖。也就是見縫插針,盡量推遲X鎖的加鎖時間,在update期間允許讀操作,可以進一步提高效率。
4)死鎖和活鎖
死鎖(Dead lock):多個並發運行的事務之間出現循環等待,即每個事務擁有部分鎖資源,又渴望獲得對方的鎖資源,導致任何一個事務都沒法獲得全部資源來完成整個事務,稱為死鎖。
例如下面的例子,Ta申請了R1的鎖,Tb申請了R2的鎖,這兩者是沒有沖突的,你申請你的,我申請我的。之後Ta又申請了R2的鎖,Tb又申請了R1的鎖,這個時候就很尷尬了,因為兩者都會進入等待,等待自己的鎖被釋放,於是進入了循環等待,兩個事務都沒法獲得全部的資源。
活鎖(Live Lock):盡管其他事務都在有限長的時間內獲得了鎖資源,但是由於系統調度的問題,某個事務等待了很久依然沒有獲得該資源,稱為活鎖。
例如下面的例子,對於數據R,T1,T2申請得到了S鎖,進行讀操作,這時T來申請X鎖,發現有S鎖,於是進行等待,之後又有T3,T4...來進行讀操作,根據定義可以繼續申請到S鎖,這樣T在下一次重新申請的時候依然會發現R上還是有S鎖,又要繼續等待,這就稱為活鎖,也被稱為餓死現象。
解決方案:
對於活鎖,解決方案比較簡單,可以采用FIFO,先進先出的調度方案來進行解決。
對於死鎖,有兩類解決方案,如下。
(1) Solving(permit it occurs, but can solve it)
- TimeOut,也就是給每個事務的等待時間設置了一個常量,如果等待時間超過閾值,則認為發生死鎖,則將該事務kill掉,稍後重新執行,在小系統裏使用;
- 等待圖法,根據事務和等待關系構造等待圖,對等待圖進行判環就可以發現是否出現了死鎖,檢查是否出現環的時機有兩種主要方案,一是新填加邊的時候進行判環;二是定期檢查,當判定為死鎖後,則需要在環中挑選一個犧牲者,然後將之kill掉,最後在重新執行那個犧牲者;
(2) Prevention(don’t let it occur)
- 規定所有的鎖在初始化階段需要全部申請到:這樣要麽獲得全部鎖,執行語句,要麽全部都沒有獲得,不會出現擁有部分鎖資源的情況。(數據庫系統裏不太現實)
- 給資源進行排序,必須按規定從高到低進行申請:這樣比如兩個事務都要申請R1,R2的鎖,第一個事務申請到R1的時候,第二個事務是沒有辦法先申請到R2的鎖的,因為必須按順序先等待R1的鎖被釋放,申請到R1的鎖,才能申請R2的鎖。(數據庫系統裏不太現實)
- 事務重置法:數據庫中比較實用的方法。具體來說就是給每個事務定義一個時間戳(Time Stamp),該時間戳既可以作為TID,也可以用來比較兩個事務的年齡。在發生沖突的時候,我們可以比較兩個事務的年齡,這時候就有兩個策略:i)Wait-die:年老 等待 年輕 ,即遇到碰撞,如果當前事務比較年輕,則kill掉自己,過一段時間自動按原時間戳重新執行;如果自己比較年老,則進入等待。ii)Wound-wait:年輕 等待 年老 ,即遇到碰撞,如果當前事務比較年老,則kill掉對方,如果自己比較年輕,則進入等待。註意,這兩種方案都是kill年輕的事務,並且由於事務的執行的單方向的特性,所以不會產生死鎖。另外,由於當前事務之前的事務是有限多個,所以不會出現永久等待的活鎖現象。
數據庫原理及應用-數據庫管理系統 DBMS