DB——數(shù)據(jù)的讀取和存儲方式
RDBMS是我們常見的一些存儲數(shù)據(jù)的倉庫,無論是做前端還是后端,都會接觸到。
我們常見的數(shù)據(jù)處理,都是通過sql來和數(shù)據(jù)庫做交互的,因此造成了許多人對數(shù)據(jù)庫認(rèn)知比較模糊,底層的架構(gòu)也不是很清晰,從本周開始,我們介紹些數(shù)據(jù)庫的基礎(chǔ)知識,來了解數(shù)據(jù)庫引擎是如何工作的,以及如何設(shè)計更好的索引的方法論,歡迎一起探討。
一、數(shù)據(jù)庫架構(gòu)
我們以mysql的架構(gòu)為例,進(jìn)行說明。
最上層用于連接、線程處理;第二層中包含了大多數(shù) 的核心服務(wù),包括了對 SQL 的解析、分析、優(yōu)化和緩存等功能,存儲過程、觸發(fā)器和視圖都是在這里實現(xiàn)的;而第三層就是 真正負(fù)責(zé)數(shù)據(jù)的存儲和提取的存儲引擎,例如:InnoDB、MyISAM等,文中對存儲引擎的介紹都是對 InnoDB 實現(xiàn)的分析。
二、數(shù)據(jù)存儲結(jié)構(gòu)
在整個數(shù)據(jù)庫體系結(jié)構(gòu)中,我們可以使用不同的存儲引擎來存儲數(shù)據(jù),而絕大多數(shù)存儲引擎都以二進(jìn)制的形式存儲數(shù)據(jù)。
在 InnoDB 存儲引擎中,所有的數(shù)據(jù)都被邏輯地存放在表空間中,表空間(tablespace)是存儲引擎中***的存儲邏輯單位,在表空間的下面又包括段(segment)、區(qū)(extent)、頁(page):
同一個數(shù)據(jù)庫實例的所有表空間都有相同的頁大小;默認(rèn)情況下,表空間中的頁大小都為 16KB,當(dāng)然也可以通過改變 innodb_page_size 選項對默認(rèn)大小進(jìn)行修改,需要注意的是不同的頁大小最終也會導(dǎo)致區(qū)大小的不同:
從圖中可以看出,在 InnoDB 存儲引擎中,一個區(qū)的大小最小為 1MB,頁的數(shù)量最少為 64 個。
三、隨機(jī)讀取和順序讀取
在我們常用的sql理解中,數(shù)據(jù)是以行的形式讀取出來的,其實不然,通過上述的結(jié)構(gòu),我們可以了解到,單次從磁盤讀取單位是頁,而不是行,也就是說,你即便只讀取一行記錄,從磁盤中也是會讀取一頁的,當(dāng)然了單頁讀取代價也是蠻高的,一般都會進(jìn)行預(yù)讀,這些后續(xù)再說。
1、數(shù)據(jù)的讀取路徑
關(guān)系型數(shù)據(jù)庫管理系統(tǒng)最重要的一個目標(biāo)就是,確保表或者索引中的數(shù)據(jù)是隨時可以用的。那么為了盡可能的實現(xiàn)這個目標(biāo),會使用內(nèi)存中的緩沖池來最小化磁盤活動。
每一個緩沖池都足夠大,大到可以存放許多頁,可能是成千上萬的頁。
緩沖池管理器將盡力確保經(jīng)常使用的數(shù)據(jù)被保存于池中,以避免一些不必要的磁盤讀。如果一個索引或者表頁在緩沖池中被找到,那么將會處理很快。
如果在緩沖池中,沒有找到數(shù)據(jù),會從磁盤服務(wù)器的緩沖區(qū)里面去讀取。
磁盤服務(wù)器的緩沖區(qū),如同數(shù)據(jù)庫的緩沖池讀取一樣,磁盤服務(wù)器試圖將頻繁使用的數(shù)據(jù)保留在內(nèi)存中,以降低高昂的磁盤讀取成本。這個讀取成本大概會在1ms左右。
如果磁盤服務(wù)器的緩沖池中依然沒有找到數(shù)據(jù),此時就必須要從磁盤讀取了,此時讀取又分區(qū)隨機(jī)讀取和順序讀取。
2、隨機(jī)I/O
我們必須記住一個頁包含了多條記錄,我們可能需要該頁上的所有行,也可能是其中一部分,或者是一行,但所花費的成本都是相同的,讀取一個頁,需要一次隨機(jī)I/O,大約需要10ms的時間。
時間組成:
我們可以看到,一次隨機(jī)IO需要耗時的時間還是很久的,10ms對計算機(jī)來說是一個很長的時間節(jié)點了。
3、順序讀取
如果我們需要將多個頁讀取到緩沖池中,并按順序處理它們,此時讀取的速度回變的很快,具體的原理,在B樹索引中也有過介紹,此時讀取每個頁面(4kb)所花費的時間大概為0.1ms左右,這個時間消耗對隨機(jī)IO有很大的優(yōu)勢。
以下幾種情況,會對數(shù)據(jù)進(jìn)行順序讀取。
- 全表掃描
- 全索引掃描
- 索引片掃描
- 通過聚蔟索引掃描表行
順序讀取有兩個重要的優(yōu)勢:
- 同時讀取多個頁意味著平均讀取每個頁的時間將會減少。在當(dāng)前磁盤服務(wù)器條件下,對于4kb大小的頁而言,這一值可能會低于0.1ms(40MB/s)
- 由于數(shù)據(jù)庫引擎知道需要讀取哪些頁,所有可以在頁被真正請求之前就提前將其讀取進(jìn)來,我們稱為預(yù)讀。
四、聚集索引和輔助索引
數(shù)據(jù)庫中的 B+ 樹索引可以分為聚集索引(clustered index)和輔助索引(secondary index),它們之間的***區(qū)別就是,聚集索引中存放著一條行記錄的全部信息,而輔助索引中只包含索引列和一個用于查找對應(yīng)行記錄或者主鍵記錄的指針。
關(guān)于索引的B+樹結(jié)構(gòu),網(wǎng)上有很多文章進(jìn)行分析了,我們就不在一一介紹。