你知道如何建立數(shù)據(jù)庫(kù)嗎?動(dòng)態(tài)編程,貪婪算法和啟發(fā)式?大數(shù)據(jù)中數(shù)據(jù)庫(kù)又是如何工作的?如果你對(duì)大數(shù)據(jù)專業(yè)有濃厚的興趣,那么你可以接著看看以下內(nèi)容。
優(yōu)化器的真正工作是在有限的時(shí)間內(nèi)找到一個(gè)好的解決方案。大多數(shù)情況下,優(yōu)化器找不到最佳解決方案,而是找到“好的”解決方案。對(duì)于小的查詢,可以使用蠻力方法。但是有一種方法可以避免不必要的計(jì)算,因此即使是中等查詢也可以使用蠻力方法。這稱為動(dòng)態(tài)編程。
動(dòng)態(tài)編程:這兩個(gè)詞背后的想法是,許多執(zhí)行計(jì)劃非常相似。
它們共享相同的(A JOIN B)子樹(shù)。因此,與其在每個(gè)計(jì)劃中都不計(jì)算此子樹(shù)的成本,我們可以對(duì)其進(jìn)行一次計(jì)算,保存計(jì)算的成本,并在再次看到此子樹(shù)時(shí)重新使用它。為了避免對(duì)部分結(jié)果進(jìn)行額外的計(jì)算,我們使用了記憶。
使用這種技術(shù),而不是(2 * N)!/(N + 1)!時(shí)間復(fù)雜度,我們“只”有3 ñ。在我們前面的具有4個(gè)聯(lián)接中,這意味著從336的順序傳遞到81。如果你通過(guò)8個(gè)聯(lián)接(不大)進(jìn)行較大的查詢,則意味著從57 657 600傳遞到6561。
在你已經(jīng)了解動(dòng)態(tài)編程或?qū)λ惴ňǖ那闆r下才能更好的運(yùn)用:
procedure findbestplan(S)
if (bestplan[S].cost infinite)
return bestplan[S]
// else bestplan[S] has not been computed earlier, compute it now
if (S contains only 1 relation)
set bestplan[S].plan and bestplan[S].cost based on the best way
of accessing S /* Using selections on S and indices on S */
else for each non-empty subset S1 of S such that S1 != S
P1= findbestplan(S1)
P2= findbestplan(S - S1)
A = best algorithm for joining results of P1 and P2
cost = P1.cost + P2.cost + cost of A
if cost < bestplan[S].cost
bestplan[S].cost = cost
bestplan[S].plan = “execute P1.plan; execute P2.plan;
join results of P1 and P2 using A”
return bestplan[S]
對(duì)于更大的查詢,你仍然可以采用動(dòng)態(tài)編程方法,但是要使用額外的規(guī)則(或啟發(fā)式方法)來(lái)消除可能性:
如果僅分析某種類(lèi)型的計(jì)劃(例如,左深樹(shù)),則最終得到n * 2 n而不是3 n
如果添加邏輯規(guī)則來(lái)避免針對(duì)某些模式的計(jì)劃(例如“如果表作為給定謂詞的索引,則不要嘗試對(duì)表進(jìn)行合并聯(lián)接,而僅對(duì)索引進(jìn)行嘗試”),它將減少可能性的數(shù)量而不會(huì)損害盡可能最好的解決方案。如果我們?cè)诹魃咸砑右?guī)則(例如“在所有其他關(guān)系操作之前執(zhí)行聯(lián)接操作”),那么它也會(huì)減少很多可能性。
對(duì)于非常大的查詢或具有非??斓拇鸢?但不是非??斓牟樵?的情況,則使用另一種算法,即貪婪算法。這個(gè)想法是遵循規(guī)則(或啟發(fā)式)以增量方式構(gòu)建查詢計(jì)劃。使用此規(guī)則,貪婪算法一次找到一個(gè)問(wèn)題的最佳解決方案。該算法從一個(gè)JOIN開(kāi)始查詢計(jì)劃。然后,在每個(gè)步驟中,算法都會(huì)使用相同的規(guī)則將新的JOIN添加到查詢計(jì)劃中。
假設(shè)我們有一個(gè)查詢,其中包含5個(gè)表(A,B,C,D和E)上的4個(gè)聯(lián)接。為了簡(jiǎn)化問(wèn)題,我們僅將嵌套聯(lián)接作為可能的聯(lián)接。讓我們使用“使用成本最低的聯(lián)接”規(guī)則。任意從5個(gè)表之一開(kāi)始(讓我們選擇A),用A來(lái)計(jì)算每次連接的成本(A是內(nèi)部或外部關(guān)系)。會(huì)發(fā)現(xiàn)A JOIN B成本最低,然后使用A JOIN B(A JOIN B是內(nèi)部或外部關(guān)系)的結(jié)果來(lái)計(jì)算每個(gè)連接的成本,(A JOIN B)JOIN C提供了最佳成本,然后使用(A JOIN B)JOIN C的結(jié)果來(lái)計(jì)算每個(gè)聯(lián)接的成本,最后我們找到了計(jì)劃((((A JOIN B)JOIN C)JOIN D)JOIN E)。
由于我們從A任意開(kāi)始,因此我們可以對(duì)B,C,D,E都應(yīng)用相同的算法。然后以最低的成本保留計(jì)劃。對(duì)于完整的動(dòng)態(tài)編程版本,該算法的成本為O(N * log(N))對(duì)O(3 N)。如果你有20個(gè)聯(lián)接的大型查詢,則意味著26 vs 3 486 784 401。
該算法的問(wèn)題在于,如果我們保持此聯(lián)接并添加新聯(lián)接,則假定在2個(gè)表之間找到最佳聯(lián)接將為我們帶來(lái)最佳成本。但:即使A JOIN B給出了A,B和C之間的最佳成本,(A JOIN C)JOIN B可能比(A JOIN B)JOIN C更好的結(jié)果。為了改善結(jié)果,你可以使用不同的規(guī)則運(yùn)行多種貪婪算法,并保持最佳計(jì)劃。
資料管理員
在此步驟中,查詢管理器正在執(zhí)行查詢,并且需要表和索引中的數(shù)據(jù)。它要求數(shù)據(jù)管理器獲取數(shù)據(jù),但是有兩個(gè)問(wèn)題:
關(guān)系數(shù)據(jù)庫(kù)使用事務(wù)模型。因此,你無(wú)法隨時(shí)獲取任何數(shù)據(jù),因?yàn)槠渌丝赡軙?huì)同時(shí)使用/修改數(shù)據(jù)。
數(shù)據(jù)檢索是數(shù)據(jù)庫(kù)中最慢的操作,因此數(shù)據(jù)管理器必須足夠聰明才能獲取并將數(shù)據(jù)保留在內(nèi)存緩沖區(qū)中。
在這一部分中,我們將看到關(guān)系數(shù)據(jù)庫(kù)如何處理這兩個(gè)問(wèn)題。我不會(huì)談?wù)摂?shù)據(jù)管理器獲取數(shù)據(jù)的方式,因?yàn)樗皇亲钪匾?本文足夠長(zhǎng)!)。
緩存管理器
正如我已經(jīng)說(shuō)過(guò)的,數(shù)據(jù)庫(kù)的主要瓶頸是磁盤(pán)I / O。為了提高性能,現(xiàn)代數(shù)據(jù)庫(kù)使用高速緩存管理器。
查詢執(zhí)行程序不是直接從文件系統(tǒng)獲取數(shù)據(jù),而是向高速緩存管理器請(qǐng)求數(shù)據(jù)。高速緩存管理器具有一個(gè)稱為緩沖池的內(nèi)存中高速緩存。從內(nèi)存中獲取數(shù)據(jù)極大地加快了數(shù)據(jù)庫(kù)的速度。很難給出一個(gè)數(shù)量級(jí),因?yàn)樗Q于你需要執(zhí)行的操作:
順序訪問(wèn)(例如:全面掃描)與隨機(jī)訪問(wèn)(例如:按行ID進(jìn)行訪問(wèn));讀與寫(xiě);數(shù)據(jù)庫(kù)使用的磁盤(pán)類(lèi)型:7.2k / 10k / 15k rpm硬盤(pán),固態(tài)硬盤(pán),RAID 1/5 /…內(nèi)存比磁盤(pán)快100到10萬(wàn)倍會(huì)導(dǎo)致另一個(gè)問(wèn)題。高速緩存管理器需要在查詢執(zhí)行程序使用它們之前獲取內(nèi)存中的數(shù)據(jù)。否則查詢管理器必須等待慢速磁盤(pán)中的數(shù)據(jù)。此問(wèn)題稱為預(yù)取。查詢執(zhí)行器知道它需要的數(shù)據(jù),因?yàn)樗啦樵兊娜苛鞒?,并且知道具有統(tǒng)計(jì)信息的磁盤(pán)上的數(shù)據(jù)。
當(dāng)查詢執(zhí)行程序正在處理其第一堆數(shù)據(jù)時(shí),它要求緩存管理器預(yù)加載第二組數(shù)據(jù),當(dāng)它開(kāi)始處理第二組數(shù)據(jù)時(shí),它要求CM預(yù)加載第三束,并通知CM可以從緩存中清除第一束。CM將所有這些數(shù)據(jù)存儲(chǔ)在其緩沖池中。為了知道是否仍然需要數(shù)據(jù),緩存管理器添加了有關(guān)緩存數(shù)據(jù)的額外信息(稱為閂鎖)。
有時(shí)查詢執(zhí)行器不知道需要什么數(shù)據(jù),而某些數(shù)據(jù)庫(kù)不提供此功能。取而代之的是,他們使用推測(cè)性預(yù)取或順序預(yù)取。為了監(jiān)視預(yù)取的工作狀況,現(xiàn)代數(shù)據(jù)庫(kù)提供了一個(gè)稱為“緩沖區(qū)/緩存命中率”的指標(biāo)。命中率顯示在不要求磁盤(pán)訪問(wèn)的情況下在緩沖區(qū)高速緩存中找到請(qǐng)求數(shù)據(jù)的頻率。
但是,緩沖區(qū)是有限的內(nèi)存量。因此,它需要?jiǎng)h除一些數(shù)據(jù)才能加載新數(shù)據(jù)。加載和清除緩存在磁盤(pán)和網(wǎng)絡(luò)I / O方面要付出一定的代價(jià)。如果你有一個(gè)經(jīng)常執(zhí)行的查詢,則始終加載然后清除此查詢使用的數(shù)據(jù)并不是很有效。為了解決此問(wèn)題,現(xiàn)代數(shù)據(jù)庫(kù)使用緩沖區(qū)替換策略。
緩沖區(qū)替換策略
大多數(shù)現(xiàn)代數(shù)據(jù)庫(kù)(至少是SQL Server,MySQL,Oracle和DB2)都使用LRU算法。
LRU
LRU代表大號(hào)東- [R ecently ü sed的。該算法的思想是將最近使用過(guò)的數(shù)據(jù)保存在緩存中,因此更有可能再次使用。
這是一個(gè)視覺(jué)示例:
在這個(gè)簡(jiǎn)單的示例中,緩沖區(qū)可以存儲(chǔ)3個(gè)元素:
1:緩存管理器使用數(shù)據(jù)1并將數(shù)據(jù)放入空緩沖區(qū)
2:CM使用數(shù)據(jù)4并將數(shù)據(jù)放入半裝入的緩沖區(qū)
3:CM使用數(shù)據(jù)3并將數(shù)據(jù)放入半載緩沖區(qū)
4:CM使用數(shù)據(jù)9。緩沖區(qū)已滿,因此數(shù)據(jù)1被刪除, 因?yàn)樗亲罱褂玫臄?shù)據(jù)。數(shù)據(jù)9被添加到緩沖區(qū)中
5:CM使用數(shù)據(jù)4。數(shù)據(jù)4已在緩沖區(qū)中,因此它再次成為最近使用的第一個(gè)數(shù)據(jù)。
6:CM使用數(shù)據(jù)1。緩沖區(qū)已滿,因此數(shù)據(jù)9被刪除, 因?yàn)樗亲罱褂玫臄?shù)據(jù)。數(shù)據(jù)1被添加到緩沖區(qū)
…
該算法效果很好,但存在一些局限性。如果在一張大桌子上進(jìn)行全面掃描怎么辦?換句話說(shuō),當(dāng)表/索引的大小大于緩沖區(qū)的大小時(shí)會(huì)發(fā)生什么?使用此算法將刪除高速緩存中的所有先前值,而完全掃描中的數(shù)據(jù)可能僅使用一次。
權(quán)重是使用數(shù)據(jù)的次數(shù),如果將一堆新數(shù)據(jù)加載到緩存中,則不會(huì)刪除舊的但經(jīng)常使用的數(shù)據(jù)(因?yàn)樗鼈兊臋?quán)重更高)。但是,如果不再使用舊數(shù)據(jù),該算法便無(wú)法將其保留在緩存中。因此,如果不使用數(shù)據(jù),權(quán)重會(huì)隨著時(shí)間的推移而降低。
權(quán)重的計(jì)算成本很高,這就是為什么SQL Server僅使用K = 2的原因。該值在可接受的開(kāi)銷(xiāo)下表現(xiàn)良好。要更深入地了解LRU-K,可以閱讀原始研究論文(1993年):用于數(shù)據(jù)庫(kù)磁盤(pán)緩沖的LRU-K頁(yè)面替換算法。
當(dāng)然,還有其他算法可以管理緩存,例如
2Q(類(lèi)似于LRU-K的算法)
時(shí)鐘(類(lèi)似于LRU-K的算法)
MRU(最近使用,使用與LRU相同的邏輯,但使用另一條規(guī)則)
LRFU(最近和經(jīng)常使用的最少)
一些數(shù)據(jù)庫(kù)允許使用默認(rèn)算法以外的其他算法。寫(xiě)緩沖區(qū):在數(shù)據(jù)庫(kù)中,你還擁有寫(xiě)緩沖區(qū),用于存儲(chǔ)數(shù)據(jù)并將數(shù)據(jù)按束刷新到磁盤(pán)上,而不是一一寫(xiě)入數(shù)據(jù)并產(chǎn)生許多單個(gè)磁盤(pán)訪問(wèn)權(quán)限。
緩沖區(qū)存儲(chǔ)的是頁(yè)面(數(shù)據(jù)的最小單位)而不是行(這是查看數(shù)據(jù)的邏輯/人為方式)。如果頁(yè)面已被修改且未寫(xiě)入磁盤(pán),則緩沖池中的頁(yè)面是臟的。有多種算法可以決定在磁盤(pán)上寫(xiě)入臟頁(yè)的最佳時(shí)間,但是它與事務(wù)的概念高度相關(guān)。
ACID事務(wù)是確保以下四件事的工作單元:
原子性:即使持續(xù)10小時(shí),交易還是“全有還是全無(wú)”。如果事務(wù)崩潰,則狀態(tài)返回到事務(wù)之前(事務(wù)回滾)。
隔離度:如果2個(gè)事務(wù)A和B同時(shí)運(yùn)行,則無(wú)論A在事務(wù)B之前/之后還是期間完成,事務(wù)A和B的結(jié)果都必須相同。
持久性:提交事務(wù)(即成功結(jié)束)后,無(wú)論發(fā)生什么情況(崩潰或錯(cuò)誤),數(shù)據(jù)都會(huì)保留在數(shù)據(jù)庫(kù)中。
一致性:僅將有效數(shù)據(jù)(就關(guān)系約束和功能約束而言)寫(xiě)入數(shù)據(jù)庫(kù)。一致性與原子性和隔離性有關(guān)。
在同一事務(wù)中,你可以運(yùn)行多個(gè)SQL查詢來(lái)讀取,創(chuàng)建,更新和刪除數(shù)據(jù)。當(dāng)兩個(gè)事務(wù)使用相同的數(shù)據(jù)時(shí),混亂就開(kāi)始了。經(jīng)典示例是從帳戶A到帳戶B的資金轉(zhuǎn)帳。假設(shè)你有2筆交易:
交易1從帳戶A收取100 $,并將其轉(zhuǎn)入帳戶B;交易2從帳戶A收取50 $,并將其轉(zhuǎn)入帳戶B。
如果我們回到ACID屬性:
原子性確保無(wú)論在T1期間發(fā)生什么情況(服務(wù)器崩潰,網(wǎng)絡(luò)故障...),你都不會(huì)遇到從A撤回100 $而沒(méi)有給B的情況(這種情況是不一致的) 。
I solation確保如果T1和T2同時(shí)發(fā)生,最終A將被收取150 $,B被給予150 $,而不是,例如,A會(huì)被收取150 $,而B(niǎo)僅被給予$ 50,因?yàn)門(mén)2已部分刪除了操作T1的狀態(tài)(這種情況也是不一致的狀態(tài))。
持久性可確保如果T1提交后數(shù)據(jù)庫(kù)崩潰,T1將不會(huì)消失。
一致性確保不會(huì)在系統(tǒng)中創(chuàng)建或銷(xiāo)毀任何資金。
大多數(shù)數(shù)據(jù)庫(kù)都添加了自己的自定義隔離級(jí)別(例如PostgreSQL,Oracle和SQL Server使用的快照隔離)。而且,大多數(shù)數(shù)據(jù)庫(kù)并沒(méi)有實(shí)現(xiàn)SQL規(guī)范的所有級(jí)別(尤其是讀取未提交的級(jí)別)。
用戶/開(kāi)發(fā)人員可以在連接開(kāi)始時(shí)覆蓋默認(rèn)的隔離級(jí)別(這是添加的非常簡(jiǎn)單的代碼行)。
并發(fā)控制
確保隔離,一致性和原子性的真正問(wèn)題是對(duì)同一數(shù)據(jù)的寫(xiě)操作(添加,更新和刪除):
如果所有事務(wù)都僅讀取數(shù)據(jù),則它們可以在不修改另一事務(wù)行為的情況下同時(shí)工作。
如果(至少)一個(gè)事務(wù)正在修改其他事務(wù)讀取的數(shù)據(jù),則數(shù)據(jù)庫(kù)需要找到一種對(duì)其他事務(wù)隱藏此修改的方法。此外,還需要確保不會(huì)被其他未看到修改后的數(shù)據(jù)的事務(wù)擦除此修改。
此問(wèn)題稱為并發(fā)控制。
解決此問(wèn)題的最簡(jiǎn)單方法是一個(gè)接一個(gè)地(即順序地)運(yùn)行每個(gè)事務(wù)。但這根本不是可擴(kuò)展的,并且只有一個(gè)內(nèi)核在多處理器/內(nèi)核服務(wù)器上工作,效率不是很高……
解決此問(wèn)題的理想方法是每次創(chuàng)建或取消交易時(shí):監(jiān)視所有交易的所有操作;檢查兩個(gè)(或多個(gè))交易的部分是否存在沖突,因?yàn)樗鼈冋谧x取/修改相同的數(shù)據(jù);對(duì)沖突事務(wù)中的操作進(jìn)行重新排序以減小沖突部分的大小;以一定順序執(zhí)行沖突部分(非沖突事務(wù)仍在并發(fā)運(yùn)行)。
鎖管理器:為了解決此問(wèn)題,大多數(shù)數(shù)據(jù)庫(kù)都使用鎖和/或數(shù)據(jù)版本控制。
悲觀鎖定
鎖定背后的想法是:如果交易需要數(shù)據(jù),它鎖定數(shù)據(jù)如果另一筆交易也需要此數(shù)據(jù),它必須等到第一個(gè)事務(wù)釋放數(shù)據(jù)。這稱為排他鎖。但是,對(duì)于僅需要讀取數(shù)據(jù)的事務(wù)使用排他鎖非常昂貴,因?yàn)樗鼤?huì)強(qiáng)制其他只希望讀取相同數(shù)據(jù)的事務(wù)等待。這就是為什么還有另一種類(lèi)型的鎖,即共享鎖。
使用共享鎖:如果交易只需要讀取數(shù)據(jù)A,它“共享鎖定”數(shù)據(jù)并讀取數(shù)據(jù),如果第二筆交易也只需要讀取數(shù)據(jù)A;它“共享鎖定”數(shù)據(jù)并讀取數(shù)據(jù),如果第三筆交易需要修改數(shù)據(jù)A,它“獨(dú)占鎖定”數(shù)據(jù),但它必須等到其他2個(gè)事務(wù)釋放它們的共享鎖后才能將獨(dú)占鎖定應(yīng)用于數(shù)據(jù)A。盡管如此,如果將數(shù)據(jù)作為排他鎖,則僅需要讀取數(shù)據(jù)的事務(wù)將不得不等待排他鎖的結(jié)尾才能在數(shù)據(jù)上放置共享鎖。
鎖管理器是提供和釋放鎖的過(guò)程。在內(nèi)部,它將鎖存儲(chǔ)在哈希表中(其中的鍵是要鎖定的數(shù)據(jù)),并知道每個(gè)數(shù)據(jù):哪些事務(wù)鎖定了數(shù)據(jù),哪些事務(wù)正在等待數(shù)據(jù)。
但是使用鎖可能會(huì)導(dǎo)致2個(gè)事務(wù)永遠(yuǎn)等待數(shù)據(jù)的情況:
在此圖中:
事務(wù)A擁有對(duì)data1的排他鎖,正在等待獲取data2;事務(wù)B在data2上具有排他鎖,并且正在等待獲取data1,這稱為死鎖。
在死鎖期間,鎖管理器選擇要取消(回滾)的事務(wù)以刪除死鎖。這個(gè)決定并不容易:是否最好殺死修改了最少數(shù)據(jù)量的事務(wù)(因此將產(chǎn)生最便宜的回滾)?最好是因?yàn)榱硪还P交易的用戶等待了更長(zhǎng)的時(shí)間而取消了最老的交易?是否最好取消將花費(fèi)較少時(shí)間完成的交易(并避免可能的饑餓)?如果發(fā)生回滾,此回滾將影響多少交易?但是在做出選擇之前,它需要檢查是否存在死鎖。
哈希表可以看作是一個(gè)圖形(就像前面的圖中一樣)。如果圖中存在周期,則存在死鎖。由于檢查周期非常昂貴(因?yàn)閹в兴墟i的圖相當(dāng)大),因此通常使用一種更簡(jiǎn)單的方法:使用timeout。如果在此超時(shí)時(shí)間內(nèi)未給出鎖定,則事務(wù)將進(jìn)入死鎖狀態(tài)。
鎖管理器還可以在提供鎖之前檢查該鎖是否會(huì)產(chǎn)生死鎖。但是,完美地做到這一點(diǎn)在計(jì)算上又很昂貴。因此,這些預(yù)檢查通常是一組基本規(guī)則。
兩相鎖定
確保純隔離的最簡(jiǎn)單方法是在事務(wù)開(kāi)始時(shí)獲取鎖,然后在事務(wù)結(jié)束時(shí)釋放鎖。這意味著事務(wù)必須在開(kāi)始之前等待所有鎖,并且在事務(wù)結(jié)束時(shí)釋放由事務(wù)持有的鎖。它可以工作,但 會(huì)浪費(fèi)大量時(shí)間來(lái)等待所有鎖。
更快的方法是兩階段鎖定協(xié)議(DB2和SQL Server使用),該協(xié)議將事務(wù)分為兩個(gè)階段:
事務(wù)可以獲取鎖,但不能釋放任何鎖的增長(zhǎng)階段。
在收縮階段,事務(wù)可以釋放鎖(針對(duì)已經(jīng)處理并且不會(huì)再次處理的數(shù)據(jù)),但是無(wú)法獲得新的鎖。
這兩個(gè)簡(jiǎn)單規(guī)則的思想是:
釋放不再使用的鎖,以減少等待這些鎖的其他事務(wù)的等待時(shí)間,以防止在交易開(kāi)始后交易會(huì)修改數(shù)據(jù)并因此與交易獲取的第一個(gè)數(shù)據(jù)不一致的情況。該協(xié)議運(yùn)行良好,除非修改(取消)了修改數(shù)據(jù)并釋放關(guān)聯(lián)鎖的事務(wù)。你可能最終遇到另一個(gè)事務(wù)讀取修改后的值而該值將被回滾的情況。為避免此問(wèn)題,必須在事務(wù)結(jié)束時(shí)釋放所有排他鎖。
當(dāng)然,實(shí)際的數(shù)據(jù)庫(kù)使用的是更復(fù)雜的系統(tǒng),其中涉及更多類(lèi)型的鎖(例如意圖鎖)和更多的粒度(行,頁(yè)面,分區(qū),表,表空間上的鎖),但是這種想法仍然存在相同的。
版本控制的思想是:每個(gè)交易都可以同時(shí)修改相同的數(shù)據(jù);每筆交易都有其自己的數(shù)據(jù)副本(或版本)。
如果2個(gè)事務(wù)修改了相同的數(shù)據(jù),則僅接受一個(gè)修改,而另一個(gè)則被拒絕,并且關(guān)聯(lián)的事務(wù)將回滾(并可能重新運(yùn)行)。由于以下原因,它提高了性能:讀者交易不會(huì)阻止作家交易,作家交易不會(huì)阻止讀者交易“胖而慢”的鎖管理器沒(méi)有任何開(kāi)銷(xiāo)。
一切都比鎖好,除非兩個(gè)事務(wù)寫(xiě)入相同的數(shù)據(jù)。此外,你可能很快就會(huì)面臨巨大的磁盤(pán)空間開(kāi)銷(xiāo)。
數(shù)據(jù)版本控制和鎖定是兩個(gè)不同的愿景:樂(lè)觀鎖定與悲觀鎖定。他們都有優(yōu)點(diǎn)和缺點(diǎn);這實(shí)際上取決于用例(更多的讀取還是更多的寫(xiě)入)。
某些數(shù)據(jù)庫(kù),例如DB2(直到DB2 9.7)和SQL Server(快照隔離除外)僅使用鎖。其他類(lèi)似PostgreSQL,MySQL和Oracle的混合方法涉及鎖和數(shù)據(jù)版本控制。
版本控制會(huì)對(duì)索引產(chǎn)生有趣的影響:有時(shí),唯一索引包含重復(fù)項(xiàng),索引所包含的條目可能比表中具有行的條目多,等等。
如果閱讀有關(guān)隔離級(jí)別不同的部分,則增加隔離級(jí)別時(shí)會(huì)增加鎖的數(shù)量,因此事務(wù)等待其鎖所浪費(fèi)的時(shí)間。這就是為什么大多數(shù)數(shù)據(jù)庫(kù)默認(rèn)情況下不使用最高隔離級(jí)別(可序列化)的原因。
為了提高性能,數(shù)據(jù)庫(kù)將數(shù)據(jù)存儲(chǔ)在內(nèi)存緩沖區(qū)中。但是,如果在提交事務(wù)時(shí)服務(wù)器崩潰,則崩潰期間你仍然會(huì)丟失仍在內(nèi)存中的數(shù)據(jù),這將破壞事務(wù)的持久性。你可以將所有內(nèi)容寫(xiě)在磁盤(pán)上,但是如果服務(wù)器崩潰,最終將一半的數(shù)據(jù)寫(xiě)在磁盤(pán)上,這將破壞事務(wù)的原子性。
事務(wù)編寫(xiě)的任何修改必須撤消或完成。要解決此問(wèn)題,有兩種方法:
卷影副本/頁(yè)面:每個(gè)事務(wù)都會(huì)創(chuàng)建自己的數(shù)據(jù)庫(kù)副本(或只是數(shù)據(jù)庫(kù)的一部分)并在此副本上工作。萬(wàn)一出錯(cuò),副本將被刪除。如果成功,數(shù)據(jù)庫(kù)將使用文件系統(tǒng)技巧立即從副本切換數(shù)據(jù),然后刪除“舊”數(shù)據(jù)。
事務(wù)日志:事務(wù)日志是一個(gè)存儲(chǔ)空間。在每次將磁盤(pán)寫(xiě)入磁盤(pán)之前,數(shù)據(jù)庫(kù)都會(huì)在事務(wù)日志上寫(xiě)入信息,以便在事務(wù)崩潰/取消的情況下,數(shù)據(jù)庫(kù)知道如何刪除(或完成)未完成的事務(wù)。
當(dāng)在涉及許多事務(wù)的大型數(shù)據(jù)庫(kù)上使用時(shí),卷影副本/頁(yè)面會(huì)產(chǎn)生巨大的磁盤(pán)開(kāi)銷(xiāo)。這就是為什么現(xiàn)代數(shù)據(jù)庫(kù)使用事務(wù)日志的原因。事務(wù)日志必須存儲(chǔ)在穩(wěn)定的存儲(chǔ)器中。我不會(huì)更深入地介紹存儲(chǔ)技術(shù),但是必須(至少)使用RAID磁盤(pán)來(lái)防止磁盤(pán)故障。
大多數(shù)數(shù)據(jù)庫(kù)(至少是Oracle,SQL Server,DB2,PostgreSQL,MySQL和 SQLite)都使用預(yù)寫(xiě)日志記錄協(xié)議(WAL)處理事務(wù)日志。WAL協(xié)議是3條規(guī)則的集合:
1)對(duì)數(shù)據(jù)庫(kù)的每次修改都會(huì)產(chǎn)生一個(gè)日志記錄,并且在將數(shù)據(jù)寫(xiě)入磁盤(pán)之前,必須將日志記錄寫(xiě)入事務(wù)日志中。
2)日志記錄必須按順序?qū)懭?在必須在日志記錄B之前但在B之前寫(xiě)入的日志記錄A
3)提交事務(wù)后,必須在事務(wù)成功結(jié)束之前將提交順序?qū)懺谑聞?wù)日志上。
這項(xiàng)工作由日志管理器完成。在完成所有工作之后,你應(yīng)該知道與數(shù)據(jù)庫(kù)相關(guān)的所有內(nèi)容都受到“數(shù)據(jù)庫(kù)效應(yīng)”的詛咒。更嚴(yán)重的是,問(wèn)題是找到一種在保持良好性能的同時(shí)寫(xiě)入日志的方法。如果事務(wù)日志上的寫(xiě)入太慢,它們將減慢所有操作。
數(shù)據(jù)庫(kù)必須回滾事務(wù)有多種原因:因?yàn)橛脩羧∠?,由于服?wù)器或網(wǎng)絡(luò)故障,因?yàn)槭聞?wù)破壞了數(shù)據(jù)庫(kù)的完整性(例如,你對(duì)列具有UNIQUE約束,并且事務(wù)添加了重復(fù)項(xiàng))。
事務(wù)期間的每個(gè)操作(添加/刪除/修改)都會(huì)生成一個(gè)日志。該日志記錄由以下內(nèi)容組成:
LSN:一個(gè)獨(dú)特的大號(hào)OG小號(hào)層序Ñ棕土。該LSN按時(shí)間順序給出*。這意味著,如果操作A在操作B之前發(fā)生,則日志A的LSN將低于日志B的LSN。
TransID:產(chǎn)生該操作的事務(wù)的ID。
PageID:修改后的數(shù)據(jù)在磁盤(pán)上的位置。磁盤(pán)上的最小數(shù)據(jù)量是一個(gè)頁(yè)面,因此數(shù)據(jù)的位置就是包含該數(shù)據(jù)的頁(yè)面的位置。
PrevLSN:指向同一事務(wù)產(chǎn)生的先前日志記錄的鏈接。
撤消操作:消除操作影響的一種方法
例如,如果操作是更新,則UNDO將存儲(chǔ)更新之前的更新元素的值/狀態(tài)(物理UNDO),或者存儲(chǔ)反向操作以返回到先前狀態(tài)(邏輯UNDO)**。
REDO:重播操作的一種方式
同樣,有兩種方法可以做到這一點(diǎn)。你可以在操作之后存儲(chǔ)元素的值/狀態(tài),或者在操作本身中存儲(chǔ)元素以重播它。
此外,磁盤(pán)上的每個(gè)頁(yè)面(用于存儲(chǔ)數(shù)據(jù),而不是日志)具有修改數(shù)據(jù)的最后操作的日志記錄(LSN)的ID。
每個(gè)日志都有一個(gè)唯一的LSN。鏈接的日志屬于同一事務(wù)。日志按時(shí)間順序鏈接(鏈接列表的最后一個(gè)日志是最后一個(gè)操作的日志)。為避免日志寫(xiě)入成為主要瓶頸,使用了日志緩沖區(qū)。
當(dāng)查詢執(zhí)行者要求修改時(shí):
1)緩存管理器將修改存儲(chǔ)在其緩沖區(qū)中。
2)日志管理器將關(guān)聯(lián)的日志存儲(chǔ)在其緩沖區(qū)中。
3)在這一步,查詢執(zhí)行者認(rèn)為操作已完成(因此可以要求其他修改)
4)然后(稍后),日志管理器將日志寫(xiě)入事務(wù)日志中。何時(shí)寫(xiě)入日志的決定是由算法完成的。
5)然后(稍后),緩存管理器將修改內(nèi)容寫(xiě)入磁盤(pán)。何時(shí)將數(shù)據(jù)寫(xiě)入磁盤(pán)的決定是由算法決定的。
提交事務(wù)后,這意味著對(duì)于事務(wù)中的每個(gè)操作,都將完成步驟1、2、3、4、5。寫(xiě)入事務(wù)日志的速度很快,因?yàn)樗皇?ldquo;在事務(wù)日志中的某處添加日志”,而將數(shù)據(jù)寫(xiě)入磁盤(pán)則更為復(fù)雜,因?yàn)樗?ldquo;以快速讀取數(shù)據(jù)的方式寫(xiě)入數(shù)據(jù)”。
竊取和強(qiáng)制政策
出于性能原因,可能在提交后執(zhí)行步驟5,因?yàn)槿绻l(fā)生崩潰,仍然可以使用REDO日志恢復(fù)事務(wù)。這就是所謂的NO-FORCE政策。
數(shù)據(jù)庫(kù)可以選擇一個(gè)FORCE策略(即,必須在提交之前執(zhí)行步驟5),以降低恢復(fù)過(guò)程中的工作量。
另一個(gè)問(wèn)題是選擇是將數(shù)據(jù)逐步寫(xiě)入磁盤(pán)(STEAL策略),還是選擇緩沖區(qū)管理器是否需要等到提交順序一次寫(xiě)入所有內(nèi)容(NO-STEAL)。在STEAL和NO-STEAL之間進(jìn)行選擇取決于你想要的:使用UNDO日志進(jìn)行長(zhǎng)時(shí)間恢復(fù)的快速寫(xiě)入還是快速恢復(fù)?
STEAL / NO-FORCE 需要UNDO和REDO:最高的性能,但提供更復(fù)雜的日志和恢復(fù)過(guò)程(如ARIES)。這是大多數(shù)數(shù)據(jù)庫(kù)所做的選擇。
STEAL / FORCE僅需要撤消;無(wú)需竊取/無(wú)需強(qiáng)制只需要重做;無(wú)竊取/強(qiáng)制不需任何東西:最差的性能和大量的夯是必需的。
ARIES通過(guò)以下三步從崩潰中恢復(fù):
1)分析階段:恢復(fù)過(guò)程讀取完整的事務(wù)日志*,以重新創(chuàng)建崩潰期間發(fā)生的事情的時(shí)間表。它確定要回滾的事務(wù)(所有沒(méi)有提交訂單的事務(wù)都將回滾)以及崩潰時(shí)需要將哪些數(shù)據(jù)寫(xiě)入磁盤(pán)。
2)重做過(guò)程:此過(guò)程從分析期間確定的日志記錄開(kāi)始,并使用REDO將數(shù)據(jù)庫(kù)更新為崩潰前的狀態(tài)。
在重做階段,將按時(shí)間順序(使用LSN)處理REDO日志。
對(duì)于每個(gè)日志,恢復(fù)過(guò)程都會(huì)讀取磁盤(pán)上包含要修改的數(shù)據(jù)的頁(yè)面的LSN。
如果LSN(page_on_disk)> = LSN(log_record),則意味著數(shù)據(jù)已在崩潰之前被寫(xiě)入磁盤(pán)(但是該值已被日志之后和崩潰之前發(fā)生的操作所覆蓋),因此什么也不做。
如果LSN(page_on_disk)
即使對(duì)于將要回滾的事務(wù),重做也已完成,因?yàn)樗?jiǎn)化了恢復(fù)過(guò)程(但我敢肯定,現(xiàn)代數(shù)據(jù)庫(kù)不會(huì)這樣做)。
3)撤消密碼:此密碼會(huì)回退崩潰時(shí)所有未完成的事務(wù)?;貪L從每個(gè)事務(wù)的最后一個(gè)日志開(kāi)始,并以反時(shí)間順序(使用日志記錄的PrevLSN)處理UNDO日志。
在恢復(fù)期間,必須警告事務(wù)日志有關(guān)恢復(fù)過(guò)程所執(zhí)行的操作,以便磁盤(pán)上寫(xiě)入的數(shù)據(jù)與事務(wù)日志中寫(xiě)入的數(shù)據(jù)同步。一種解決方案是刪除正在撤消的事務(wù)的日志記錄,但這非常困難。而是,ARIES將補(bǔ)償日志寫(xiě)入事務(wù)日志中,該日志將邏輯上刪除要?jiǎng)h除的事務(wù)的日志記錄。
當(dāng)“手動(dòng)”取消交易或由鎖定管理器取消交易(以停止死鎖)或僅由于網(wǎng)絡(luò)故障而取消交易時(shí),則不需要分析通過(guò)。實(shí)際上,有關(guān)REDO和UNDO內(nèi)容的信息可在2個(gè)內(nèi)存表中找到:
一個(gè)事務(wù)表(存儲(chǔ)所有當(dāng)前事務(wù)的狀態(tài))
一個(gè)臟頁(yè)表(需在磁盤(pán)上寫(xiě)入數(shù)據(jù)需要存儲(chǔ))。
這些表由緩存管理器和事務(wù)管理器針對(duì)每個(gè)新事務(wù)事件進(jìn)行更新。由于它們?cè)趦?nèi)存中,因此在數(shù)據(jù)庫(kù)崩潰時(shí)會(huì)被銷(xiāo)毀。
分析階段的工作是在崩潰后使用事務(wù)日志中的信息重新創(chuàng)建兩個(gè)表。*為了加快分析過(guò)程,ARIES提供了checkpoint的概念。想法是不時(shí)在磁盤(pán)上寫(xiě)入事務(wù)表,臟頁(yè)表的內(nèi)容以及該寫(xiě)入時(shí)的最后LSN的內(nèi)容,以便在分析過(guò)程中僅分析此LSN之后的日志。
當(dāng)你不得不在錯(cuò)誤的NoSQL數(shù)據(jù)庫(kù)和堅(jiān)如磐石的關(guān)系數(shù)據(jù)庫(kù)之間進(jìn)行選擇時(shí),請(qǐng)三思而后行。有些NoSQL數(shù)據(jù)庫(kù)很棒。但是他們還很年輕,正在回答涉及一些應(yīng)用程序的特定問(wèn)題。
經(jīng)過(guò)以上了解,大家應(yīng)該明白大數(shù)據(jù)中數(shù)據(jù)庫(kù)是如何工作的了,想要學(xué)習(xí)更深層次的大數(shù)據(jù)專業(yè)知識(shí),可以到AAA教育官網(wǎng)了解一下,大數(shù)據(jù)分析專業(yè),互聯(lián)網(wǎng)熱門(mén)行業(yè),技術(shù)含量高,無(wú)論是找工作還是自我提升都是不錯(cuò)的選擇。
填寫(xiě)下面表單即可預(yù)約申請(qǐng)免費(fèi)試聽(tīng)!怕錢(qián)不夠?可先就業(yè)掙錢(qián)后再付學(xué)費(fèi)! 怕學(xué)不會(huì)?助教全程陪讀,隨時(shí)解惑!擔(dān)心就業(yè)?一地學(xué)習(xí),可推薦就業(yè)!
?2007-2022/ 5wd995.cn 北京漫動(dòng)者數(shù)字科技有限公司 備案號(hào): 京ICP備12034770號(hào) 監(jiān)督電話:010-53672995 郵箱:bjaaa@aaaedu.cc