關(guān)系數(shù)據(jù)庫的全景圖
這篇文章討論了關(guān)系型數(shù)據(jù)庫內(nèi)部的索引和事務(wù)是如何工作的,而不深入研究特定數(shù)據(jù)庫的怪癖。我將涵蓋您應(yīng)該了解的關(guān)于RDBMS索引的一切。我將簡要涉及事務(wù)和隔離級別,以及它們?nèi)绾斡绊憣μ囟ㄊ聞?wù)的推理。
圖1.0 關(guān)系型數(shù)據(jù)庫解釋信息圖
1.什么是RDBMS?
關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS)是一種用于管理結(jié)構(gòu)化數(shù)據(jù)的軟件。它使用表格來存儲數(shù)據(jù),并支持SQL(Structured Query Language)進(jìn)行數(shù)據(jù)檢索和操作。RDBMS是一種常見的數(shù)據(jù)庫類型,包括MySQL、PostgreSQL、Oracle、SQL Server等。
2.什么是索引?
索引是一種數(shù)據(jù)結(jié)構(gòu),用于降低請求數(shù)據(jù)的查找時間。索引通過額外的存儲、內(nèi)存和維護(hù)成本(寫入速度較慢)來實(shí)現(xiàn)這一點(diǎn),使我們能夠跳過檢查每個表行的繁瑣任務(wù)。
就像教科書后面的索引一樣,它可以幫助你找到正確的頁。我不是書的愛好者,但當(dāng)我們深入研究數(shù)據(jù)庫索引時,它是一個很好的引入主題的方式。
3.為什么我們需要索引?
小量的數(shù)據(jù)是可以管理的,但是當(dāng)它們變得更大時(比如大城市的出生登記簿),事情就變得不那么簡單了。一切原來快速的東西變得更慢,太慢。
想象一下,如果您不得不在1頁上查找某些內(nèi)容,與在千頁的名單上查找相比,您的策略會發(fā)生什么變化。不,認(rèn)真地,請花一秒鐘思考一下。
不管您想出什么好策略,某個數(shù)據(jù)庫幾乎在某個時候都實(shí)現(xiàn)了您能想到的所有好策略。隨著它們的增長,系統(tǒng)會收集和存儲更多的數(shù)據(jù),最終導(dǎo)致上述問題。
我們需要索引來幫助我們盡快獲取我們需要的相關(guān)數(shù)據(jù)。
4.索引是如何工作的?
隨著數(shù)據(jù)的索引化,讀取性能會提高,但這會以寫入性能為代價,因?yàn)槟枰3炙饕淖钚?。因此,?jīng)常會提出的一個解決方案問題是按照您希望搜索的方式對數(shù)據(jù)進(jìn)行邏輯排序。這意味著如果要按名稱搜索列表,您會按名字對列表進(jìn)行排序。這種策略有一些問題。我主要將其作為讀者的問題提出:
- 如果要以多種方式搜索數(shù)據(jù)怎么辦?
- 如何處理將新數(shù)據(jù)添加到列表中?這是否很快?
- 如何處理更新?
- 這些任務(wù)的O標(biāo)記是多少?
不管您的原始策略如何,我們絕對需要一種方法來維護(hù)順序,以便我們可以快速獲取相關(guān)的無序數(shù)據(jù)(很快就會談到這一點(diǎn))。
5.鏈表
我們希望在互聯(lián)網(wǎng)上建立最大的系統(tǒng)設(shè)計社區(qū)!我們希望您加入我們。您可以在Twitter上找到我們。您也可以在此處聯(lián)系作者,提供反饋。
讓我們來看看下面的圖1.1。
+─────+─────────+──────────────+
| id | name | city |
+─────+─────────+──────────────+
| 1 | Mahdi | Ottawa |
| 2 | Elon | Mars |
| 3 | Jeff | Orbit |
| 4 | Klay | Oakland |
| 5 | Lebron | Los Angeles |
+─────+─────────+──────────────+
圖1.1 可以快速從磁盤讀取的小表格
底層數(shù)據(jù)在存儲中分散,沒有順序,似乎是隨機(jī)分配的。如今,大多數(shù)生產(chǎn)服務(wù)器都配備了SSD,但有些情況下,您可能需要使用(HDD)傳統(tǒng)硬盤,但老實(shí)說,這樣的情況越來越少,因?yàn)镾SD的價格大幅下降。
6.SSD與HDD
現(xiàn)在,將這么多數(shù)據(jù)讀入內(nèi)存非???,相對來說也很容易進(jìn)行掃描。那么,如果我們正在搜索的數(shù)據(jù)無法完全緩存在內(nèi)存中,或者從磁盤讀取所有數(shù)據(jù)所需的時間太長呢?
+──────────+─────────+───────────────────+
| id | name | city |
+──────────+─────────+───────────────────+
| 1 | Mahdi | Ottawa |
| 2 | Elon | Mars |
| 3 | Jeff | Orbit |
| 4 | Klay | Oakland |
| 5 | Lebron | Los Angeles |
| ... | ... | ... |
| 1000000 | Steph | San Francisco |
| 1001000 | Linus | Portland |
+───────+─────────+──────────────────────+
圖1.2 大表格,無法完全放入內(nèi)存,分布在磁盤上
這就是大多數(shù)開發(fā)人員會遇到的問題 - 我以前遇到過這個問題;我們需要一些字典(哈希映射)以及一種無需掃描緩慢的磁盤、讀取大量塊的方式來查找我們需要的數(shù)據(jù)是否存在。
這些被稱為索引葉節(jié)點(diǎn),它們會指定一個要索引的特定列,它們可以存儲匹配行的位置。
這些索引葉節(jié)點(diǎn)是索引列和相應(yīng)行位于磁盤上的位置之間的映射。這使我們能夠快速找到特定行,如果您引用它,就是索引列。掃描索引可以更快,因?yàn)樗且阉鞯牧械木o湊表示(字節(jié)更少),它可以節(jié)省您讀取大量塊以查找請求的數(shù)據(jù)所需的時間,并且更方便緩存,進(jìn)一步加速整個過程。
數(shù)據(jù)規(guī)模常常適得其反,平衡樹是應(yīng)對之的第一工具。
這些索引葉節(jié)點(diǎn)大小均勻,我們試圖盡可能多地存儲這些葉節(jié)點(diǎn)。由于這種結(jié)構(gòu)要求事物在邏輯上進(jìn)行排序(不是在物理上排列在磁盤上),我們需要解決快速添加和刪除數(shù)據(jù)的問題;好的老式雙向鏈表管理這一點(diǎn),更具體地說,是雙向鏈表。
7.數(shù)據(jù)塊
這里的好處有兩方面:它允許我們前向和后向讀取索引葉節(jié)點(diǎn),以及當(dāng)我們刪除或添加新行時,快速重建索引結(jié)構(gòu),因?yàn)槲覀冎皇切薷闹羔?- 強(qiáng)大的東西。
8.鏈接列表
由于這些葉節(jié)點(diǎn)在磁盤上物理上未按順序排列(請記住,指針維護(hù)雙向鏈表的排序),我們需要一種方法來獲取正確的索引葉節(jié)點(diǎn)。
(1) 平衡樹(B-Tree)
圖1.3 結(jié)構(gòu)差異:B樹與B+樹
這使您可能會想知道,您在學(xué)校討厭的B樹中犯了什么大錯誤。我明白這些東西很無聊,但它們很強(qiáng)大,值得理解。
B+樹允許我們構(gòu)建一個樹結(jié)構(gòu),其中每個中間節(jié)點(diǎn)指向其各自葉節(jié)點(diǎn)的最高節(jié)點(diǎn)值。這為我們提供了一種找到將指向所需數(shù)據(jù)的索引葉節(jié)點(diǎn)的明確路徑的方法。
這個結(jié)構(gòu)是從底層開始構(gòu)建的,以便中間節(jié)點(diǎn)覆蓋所有葉節(jié)點(diǎn),直到達(dá)到頂部的根節(jié)點(diǎn)。這個樹結(jié)構(gòu)之所以被稱為“平衡”,是因?yàn)檎麄€樹的深度是統(tǒng)一的。
(2) B-樹與B+樹
9.對數(shù)可擴(kuò)展性
我想在這里簡要提一下這個結(jié)構(gòu)的威力。當(dāng)然,大多數(shù)開發(fā)人員都意識到數(shù)據(jù)的指數(shù)增長以及理想情況下,您公司的估值。但不幸的是,數(shù)據(jù)規(guī)模常常與您作對,而平衡樹是應(yīng)對之的第一工具。
根據(jù)中間節(jié)點(diǎn)可以引用的項(xiàng)目數(shù)(M)以及整個樹(N)的深度,我們可以引用M到N個對象。
下表以M值為5來說明了這個概念。
因此,隨著索引葉節(jié)點(diǎn)數(shù)量呈指數(shù)增長,樹的高度相對于索引葉節(jié)點(diǎn)數(shù)量的增長速度非常慢(對數(shù)增長),再加上平衡樹的高度,幾乎可以立即找到指向?qū)嶋H磁盤上的相關(guān)索引葉節(jié)點(diǎn)。這與數(shù)據(jù)庫相比是一個非??斓乃俣?。
不是美麗的景象嗎?
10.什么是事務(wù)?
事務(wù)是您希望將其視為單個單位的工作。因此,它必須完全發(fā)生或完全不發(fā)生。我認(rèn)為大多數(shù)系統(tǒng)不需要手動管理事務(wù),但也有一些情況下,增加的靈活性對于實(shí)現(xiàn)所需的效果非常重要。事務(wù)主要涉及ACID中的I,即隔離。
11.什么是ACID?
這些可以自動為您執(zhí)行,以便您甚至不知道它們正在發(fā)生,或者您可以像下面這樣手動創(chuàng)建它們:
-- 手動事務(wù)與提交。
BEGIN;
SELECT * FROM people WHERE id =1;
COMMIT or ROLLBACK;
圖1.3 如何創(chuàng)建手動事務(wù)
我們將重點(diǎn)關(guān)注BEGIN和COMMIT或ROLLBACK之間的時間,以及對相同數(shù)據(jù)進(jìn)行操作的其他各種事務(wù)發(fā)生了什么。
(1) 提交/回滾
(2) 讀現(xiàn)象
在這些隔離級別中可能會發(fā)生多種讀取現(xiàn)象,了解它們對于調(diào)試系統(tǒng)并誠實(shí)地幫助理解系統(tǒng)可以容忍什么樣的不一致非常重要。
(3) 不可重復(fù)讀
Databases-08.jpeg
就像上圖所示,不可重復(fù)讀取是指在事務(wù)期間連續(xù)兩次讀取數(shù)據(jù)時,您無法獲取一致的數(shù)據(jù)視圖。在特定模式下,可以進(jìn)行并發(fā)數(shù)據(jù)庫修改,并且可能會發(fā)生您剛剛讀取的值被修改的情況,從而導(dǎo)致不可重復(fù)讀取。
(4) 臟讀
Image.png
類似地,臟讀取是指您執(zhí)行讀取,另一個事務(wù)更新相同行但沒有提交工作,然后執(zhí)行另一次讀取,您可以訪問未提交(臟)值,這不是持久的狀態(tài)更改,也與數(shù)據(jù)庫的狀態(tài)不一致。
(5) 幽靈讀
Databases-10.jpeg
幽靈讀取是另一種已提交的讀取現(xiàn)象,它發(fā)生在您主要處理聚合時。例如,您要求特定事務(wù)中的客戶數(shù)量。在連續(xù)兩次讀取之間,另一位客戶注冊或刪除他們的帳戶(已提交),這會導(dǎo)致您獲取到兩個不同的值,如果您的數(shù)據(jù)庫不支持這些事務(wù)的范圍鎖,則可能會發(fā)生這種情況。
(6) 范圍鎖
(7) 隔離級別
Databases-05-2.jpeg
SQL標(biāo)準(zhǔn)定義了4種標(biāo)準(zhǔn)隔離級別,這些級別可以并且應(yīng)該在全局配置(如果不能可靠地推斷隔離級別,可能會發(fā)生潛在問題)。
(8) 可重復(fù)讀
讓我們從可重復(fù)讀開始。這很容易理解,并為其他隔離級別奠定了基礎(chǔ)。此隔離級別確保在第一次讀取建立的事務(wù)內(nèi)進(jìn)行一致讀取。此視圖以多種方式維護(hù);某些方式會影響整個系統(tǒng)的性能,而其他方式不會,但不在本文的范圍內(nèi)。
請參考上面的圖形;一旦我們進(jìn)行了第一次讀取,該視圖將在事務(wù)持續(xù)期間被鎖定,因此在此事務(wù)的上下文之外發(fā)生的任何事情都無關(guān)緊要,無論是已提交還是未提交。
這種隔離級別保護(hù)我們免受多種已知的隔離問題的影響,主要是不可重復(fù)讀和臟讀。它確實(shí)有一些輕微的數(shù)據(jù)不一致,因?yàn)樗绘i定在特定數(shù)據(jù)庫視圖,因此在此鎖定期間的數(shù)據(jù)不相關(guān);在此期間,保持事務(wù)盡可能短是有益的。
(9) 可串行化
這種操作模式可以是最受限制和一致的,因?yàn)樗辉试S一次運(yùn)行一個查詢。
由于數(shù)據(jù)庫依次運(yùn)行查詢,從一個穩(wěn)定狀態(tài)過渡到下一個,因此不再可能發(fā)生所有類型的讀取現(xiàn)象。當(dāng)然,這里還有更多細(xì)節(jié),但大致如此。
重要的是要注意,在這種模式下需要一些重試機(jī)制,因?yàn)橛捎诓l(fā)問題,查詢可能會失敗。
較新的分布式數(shù)據(jù)庫利用此隔離級別以實(shí)現(xiàn)一致性保證。 CockroachDB 就是這樣的數(shù)據(jù)庫的一個例子。值得一看。
(10) 讀已提交
這種隔離模式不同于可重復(fù)讀,因?yàn)槊看巫x取都會創(chuàng)建自己的一致(已提交)時間快照。因此,如果我們在同一事務(wù)中執(zhí)行多次讀取,這種隔離級別容易受到幽靈讀的影響。
(11) 讀未提交
另一種是讀未提交隔離級別,它不維護(hù)任何事務(wù)鎖定,并可以看到正在發(fā)生的未提交數(shù)據(jù),從而導(dǎo)致臟讀。在某些系統(tǒng)中,這是噩夢中的東西。
這就是關(guān)于數(shù)據(jù)庫的你應(yīng)該了解的事情。