以下描述大多參考

MIT15-445

課程相關資料和

MySQL技術內幕-innodb儲存引擎

第二版。

如有需要觀看

MIT15-445

中文翻譯課程,可知乎關注 Klein Moretti(這並不是筆者的知乎,也並非打廣告,單純地推薦而已),也可B站搜尋MIT15-445關鍵字。

此係列不適合對資料庫實現原理完全空白的人群,因此建議讀者先對

MySQL技術內幕-innodb儲存引擎

第二版進行翻閱檢視,然後再閱讀並操作此文,方便更好地理解。

同時由於個人能力有限,有些地方可能理解有誤或者表述有誤,歡迎指正和討論,畢竟筆者也是半路出家/捂臉。

1資料庫儲存(disk storage)

我們實際該如何⽤磁碟上的⽂件來表示資料庫。

file storage

首先討論如何在一系列page上組織資料庫,也就是如何將這些⻚儲存在這些資料庫磁碟檔案中。

事實上,資料庫其實就是磁碟上的一個或者多個⽂件,⼤部分系統會將這些分為多個⽂件來儲存,分散的小檔案比一個超大檔案更容易錯誤修復。

有的資料庫使用裸儲存裝置區管理資料,但我們目前的階段無需這樣。

現在我們所要構建的東⻄,本質上來講,它被稱為

storage manager

,或者稱為

storage engine

。他是我們的資料庫系統中的⼀個元件。它負責維護我們在磁碟上的資料庫⽂件,基於它我們可以對這些檔案進行資料read和write。

storage manager 將這些⽂件組織為pages的集合,它將跟蹤我們要在這些page上所執行的所有read和write操作,並且跟蹤我們的pages中還有多少可用空閒空間。

概念-pages

一個page表示一個固定大小的資料塊。這些資料塊被組織在資料庫磁碟檔案。、

page中可以儲存任何資料,包括:資料庫⾥⾯的tuple,metadata, indexes, log 記錄等。總之我們必須將資料儲存在某個page中。

有些資料庫系統的page是self-contained(它自己能夠解釋自己的資料)的,因此可能需要存放除了行資料之外的一些額外資料,但行資料必須儲存在page自身中。

舉個例子,行資料指的就是 1,張三,北京,但是還好需要資料型別、是否有null值等額外的說明資料。

long |varchar |varchar

1 |張三 |北京

通常來說page是self-contained有助於故障恢復,因為當前的page不依賴其它的page,即使其它page損壞,也不會影響自身,我們的構建也會基於self-contained,當然非self-contained也是完全沒有問題的。

但是我們不會將不同型別的資料放在一個page中,就像MySQL中分為資料頁、索引頁、日誌記錄頁等型別頁。

每個page都會被賦予⼀個唯⼀的內部識別符號,資料庫系統會為⽣成這些page ID。然後我們需要一個對映層,允許我們將⼀個page ID對映到某個集合中⼀個⽂件中的某個位置。這是一個相對位置,因為我們的page大小是固定的(如果是4KB),假設我們要查詢的page在a檔案中,相對位置為1,表示為get(a,2),那麼讀取位置就是

2*4*1024

,讀取長度就是

4*1024

這樣,當我們整體移動了這個檔案之後我們依然可以準確從中查詢page,因為我們有這個page directory,根據它,我們就可以查詢page1,page2,page3……。

資料庫管理系統中有三種page 概念需要注意:

hardware page:你獲取資料最終是透過它提供的api,就像SSD或者機械硬碟,通常是4kb。

OS page:我們透過它,從儲存裝置中取出資料,並放⼊記憶體中,在Linux和Windows中,這通常使⽤了4kb⼤⼩。

database page:這是我們比較care的,由於它是我們設計界定的page,因此不同的資料庫大小不同。總體是在512 bytes-16kb之間。Oracle、DB2是4kb;postgreSQL、SQLserver是8kb;MySQL是16kb。

注意:hardware page是原子寫入儲存裝置的最低底層的東西,通常是4kb:如果我對磁碟進⾏ write和flush操作,儲存裝置只能保證每次寫⼊4kb時是原⼦的。也就是我們往磁碟寫入8kb的資料,寫了4kb之後故障奔潰了,之後磁碟恢復之後我們會得到一個不完整的4kb資料。

當然很多資料庫的database page都是可調整的,也就是mysql允許我們將database page改成4kb或者8KB。

page 儲存架構

架構意味著我們可以透過storage manager找到page,並對page進行read、write操作,也不需關心page中存放的什麼資料。這有很多方式,包括sort file 組織、hashing file 組織,通常我們使用Heap File 組織,注意他們都是一種架構理念、方式。

一個heap檔案就是一個無序的page集合,tuple被以隨機的順序儲存。也就是說我們寫入資料的順序並不是磁碟儲存的順序,storage manager 不保證資料是按照我插⼊的順序儲存在磁碟上的。

因此我們需要的API必須能夠對page進⾏讀寫和訪問,並且可以遍歷所有的page。我們會使⽤⼀些額外的元資料來

跟蹤這些page

和page中的

可用空閒空間

這樣如果我們需要插⼊新資料時,我們就知道可以在哪個page上插⼊資料了。

為了實現以上的需求,我們需要在內部組織我的heap file。我們可以使用linked list或者page directory的方式,出於綜合效率我們將使用page directory的方式,如圖所示:

1資料庫儲存(disk storage)

假設,我們的heap file中有很多page,我們需要找到某個page,並且知道哪些page是有可用空間的。

如上圖所示,page directory的方式是:

使用一個目錄對映的方式儲存page必要的資訊,裡面的每個塊的組成大概是

,這樣,我們將目錄讀取到記憶體中可以按照page_id進行排序,然後查詢就可以使用更快的查詢,比如二分查詢;

如果我們去更新⼀個page,清除它上⾯的⼀些資料,然後更新page 目錄(比如我們需要更新它上面的free_space)之後,我們就可以說我們已經清理完這個page了。

關於以上的一些可能的疑問

1-為什麼資料不是按照我們新增的順序儲存在磁碟檔案中。就大多數的傳統關係型資料庫而言,資料儲存採用page儲存,也就是b-tree的方式組織,這屬於就地更新的方式,我們的所有操作都是基於b-tree索引,b-tree中的page節點是有序的,而根據這些資訊我們就可以定位指定的磁碟檔案中的page,也就是我們不關心資料在磁碟上具體是如何儲存的。

與page儲存不同的另一種儲存方式是log儲存,通常是使用LSM-tree進行組織,這種儲存主要是為了快速海量儲存資料,主要利用磁碟順序寫操作log,然後記憶體排序後批次重新整理磁碟,也就是異地更新。如果按照wisckey論文的key value分離儲存,value log檔案中的資料就是按新增順序儲存的,因為插入是追加的,分散式kv資料庫大多使用這個資料結構,比如谷歌的levelDB,和Facebook 基於levelDB 分支開發的rocksDB,還有我們眾所周知的HBase,目前流行的時序資料庫也大多基於LSM結構。

但就結論來說,刻意把資料按照插入順序組織儲存在磁碟檔案中沒有什麼利處,LSM儲存在磁碟中的SSTable是有序的,但也不是按照插入順序的,按照指定的key進行排序我們可以容易地利用磁碟順序讀效能,然而按照順序插入沒有任何作用。

2-page 大小有什麼影響:如果我們將page設定為16kb,那麼我們directory相同的空間可以對映更多的資料,因為每個page更大。更大的page意味著我們可以更大程度順序讀取,但是我們需要額外的方式來保證一種儲存上的原子性,這讓寫⼊操作的代價變得更⾼。二者各有優劣。

page 結構佈局

1資料庫儲存(disk storage)

每個page包含一個關於page中資料內容的mete-data header。header中包括:

page size;checksum(檢測資料是否損壞);DBMS version(我們可以使用不同的api,操作不同版本的page);Transaction Visibility(事務可見性);Compression Information(壓縮資訊,我們使用了哪種演算法壓縮了資訊)……

在⼀個page中,我們可以透過兩種不同的⽅式來表示資料,我們可以透過⾯向tuple的⽅式來表示資料,還可以採⽤⼀種

log-structured

(日誌追加的方式,通常基於LSM-tree,最近的一些新興資料庫經常會採用的一種做法)的策略,我們將採用

⾯向tuple

的方式,這也是我們需要重點關注的方式。

注意,我們不能假設page中的tuple的大小是一樣的,他們的大小是不同的。因此我們不能透過簡單的相對offset去實現儲存和查詢。

實際中,我們會使用一種稱為slotted pages(槽化的page)佈局結構,拋開具體的實細節,從⾼級層⾯來講,幾乎所有的資料庫都是使用這種佈局結構來實現page 內部結構的。如圖所示:

1資料庫儲存(disk storage)

我們可以透過我們的header來實現,header⾥⾯能夠儲存基本的元資料,例如checksum或者訪問時間之類的東⻄,接著們必須有能夠儲存資料的區域,如圖在頂部我們有⼀個slot陣列,底部的空間則是我們⽤來儲存我們想儲存的資料。

slot array 對映slot 到tuples的

starting position offsets

header持續跟蹤已經使用的slots(我們可以使用一個bitmap來進行標記,又或許循序掃描空的slot),和

最後一個使用的slot

起始位置

offset

不管我如何整理我的page,也不管我怎麼去移動tuple1,我知道我始終想去第⼀個slot處找到這個tuple1,這也是它實際所在的位置。

本質上來講,slot陣列是將⼀個特定的slot對映到page上的某個偏移量上

,即根據這個偏移量,你能找到你想要的那個tuple。

我們之所以想要這個對映層的原因是,在此基礎上,我們現在就可以將這個page內的tuple移動到我們想要的任何地⽅(當你對page空間重新整理的時候會不得不移動tuple的位置)。此時,

⼀條記錄的位置

是由

page id

slot number

來⼀起確定的。我們所需要做的就是移動tuple,並更新slot陣列:告訴這個slot陣列,應該指向tuple移動後的位置。

因此每條tuple會賦予一個唯一id,通常是 page_id+slot。

如圖所示,對於整個page來說,我們從前往後對slot陣列進⾏填充,tuple資料則是從後到前進⾏填充,直到page內空間耗盡。

由於我們支援了非固定長度的tuple,因此在最後可能會存在一個tuple正好塞不下的情況,表示當前page已滿。但事實上,我們在填充的過程中可能有過刪除或者修改操作,因此,中間有可能是有空閒空隙的。此時我們我們可以進⾏⼀種稱為

vaccum

的操作(Postgres中的⼀個操作,⽤於整理資料庫)或者壓縮,也可以對資料庫進⾏掃描並整理碎⽚。我們可以在我們的⽂件系統後臺這麼做,也可以在資料庫系統中進⾏這些操作,這表明他是一種後臺的操作,而不是刪除時的實時動作。

注意:我們不會在一個page中存放不同表的tuple。一般,我們在資料庫中建立表時,資料庫就會去建立一些page,只有這個表的tuple會儲存在這些page中。

總的來說這就是⾯向tuple的page。

一般來說,我們希望將⼀個完整的tuple放在某一個單個page中,當我們想去訪問這個tuple的時候,它就在這個page上,那我們直接讀取就⾏,而不需要從多個page上找到並進行組合。但事實上,可能我們有時候tuple資料比較大,出現單個page存放不下的情況,我們稍後討論,通常此時我們需要一些指標去指向

溢位頁

說了這麼多,我們其實可以更加直觀地看一下商業資料庫中page的儲存形式:

假如我們使用的是postgresql,並且我們建立了這樣一張表,裡面有一些簡單的資料:

1資料庫儲存(disk storage)

在postgresql中,tuple的唯一id稱為ctid,它表示了該資料所在的物理位置,我們可以新增一個虛擬的列來顯示它:

1資料庫儲存(disk storage)

在ctid中,我們看到了page id:0,以及對應的slot number:1,2,3。

說明:第⼀條tuple是放在page 0上的slot 1處,它實際上並沒有儲存這個資料,當我們執⾏這個查詢時,它就能由此得出這些資料,這表示在page 0 上面存在這個已經使用的slot。

當我們刪除第二條tuple之後,查詢結果是這樣的:

1資料庫儲存(disk storage)

根據查詢的資訊可以知道,postgresql並沒有立即去整理page 空間。

因此,你可以猜一下我們插入第四條資料的時候會發生什麼:

1資料庫儲存(disk storage)

沒錯,正如我們所論述的那樣,它只是從最後的一條tuple後面新增,而不是插入第二條tuple的位置(因為我們不能假定不同的tuple都是相同固定長度的,即使是同一個表schema)。

在Postgres中有種被稱為

vaccum

的存在,你可以把它當成是資料庫中的垃圾回收器,就像Java、go語言的垃圾管理器,

vaccum

會去遍歷這些page,然後整理這些page。很明顯這屬於磁碟IO。

tuple 結構佈局

在我們的世界中,tuple只是⼀串位元組,我們拿到了slot偏移量,我們往⾥⾯寫⼊⼀些位元組,就是這樣。

資料庫需要能夠再次解釋這些位元組的實際含義,這就是為什麼要有schema的原因。比如:schema表示我有⼀個int,它的⻓度是32位。

當我在檢視我的位元組序列時,我知道該如何跳轉到不同的偏移量處來找到我想要的列(某行中的某列,也就是某個屬性)。

tuple總體是這樣的:

1資料庫儲存(disk storage)

tuple header

每個tuple都被字首了一個包含描述自身元資料的header,這些元資料包括:可見性資訊(用於併發控制),關於null值列的bitmap。另外需要注意的是header元資料中我們不需要儲存schema相關的資訊。

在我們的page中,根據相對於起始位置的偏移量來找到這個tuple,並在header跟蹤⼀些不同的東⻄,例如哪⼀個事務查詢修改了這個tuple。

然後我們還有一些其他的元資料。通常,我們⽆須將該tuple的元資料儲存在這個tuple⾥⾯。當我們儲存tuple時,我們沒必要去說,我們有四列,它們的型別是xx型別,我們可以將這種更⾼級的元資料資訊儲存在當前的page⾥,也可以放在catalog page⾥⾯。

tuple data 概覽

1資料庫儲存(disk storage)

我們必須儲存有關其實際內容的資料,通常情況下,是根據我們建立表時的順序來儲存這些tuple資料,如圖所示。關係模型並沒有表示讓你這樣做,但是大多數資料庫系統會這樣做。在有些記憶體資料庫中為了提高效能,可能會對欄位資料進行重排序(也就是位元組對齊,不瞭解的讀者參考ps1解釋),但我們不關心這個。

tuple data 詳情

我們將瞭解,在tuple中,各個屬性(列)的資料實際儲存方式,我們該如何表示它們;我們該如何儲存我們表的元資料。

從⾼級層⾯來講,一個tuple就是一個位元組陣列。資料庫管理系統的工作就是去解釋這些位元組資料:它們的屬性型別和值,某個屬性是int, double還是varchar。

首先將這些位元組陣列組織成我們的tuples,然後,當資料庫系統執⾏查詢時,去解釋這些位元組陣列中的實際內容,並生成我們世界鎖希望的資料,這會涉及到之後要討論的catalog的相關內容。資料庫使⽤這些資訊來解釋以及解密這些位元組。

在⼤部分資料庫系統中,像

int

long

double

這些固定⻓度的資料,我們所使⽤的表達⽅式是與大多數高階程式語言一致。

對於可變⻓度的型別,例如

varchar

text

以及

blob

來說,它們⾥⾯都有⼀個header,⾥⾯會儲存資料的⻓度。如果它是⼀個超級大的值,那後⾯還會跟⼀個checksum,接著,後⾯就跟的是實際的位元組序列。總的來說,是使⽤⼀個字首來告訴我們這些非定長資料的體積有多⼤。

對於

date

timestamp

型別來說,不同的資料庫中,可以有不同的實現。⼤多數系統會去儲存從1970年1⽉1⽇起的秒數或毫秒數或者微秒數來處理時間型別。本質上來說,不管你儲存的時間格式是什麼,資料庫都會儲存完整的時間戳。

以上基本上就是我們要實現的東西。

關於定點數和浮點數

浮點數,float、double,這些由IEEE⼆進位制浮點數算術標準規定,它是⼀種⽤來表示數字和CPU的規範,這種型別我們直接使用語言提供的型別儲存即可。因為是基於數字和CPU規範,CPU擁有能夠⾼效執⾏這些操作的指令,CPU透過⼀條指令就能對兩個浮點數進⾏相加或者相減。處理定點數時,我們需要額外的程式碼邏輯來對它們進⾏處理,而這就意味著需要更多的指令才能處理它們。

所以運算速度會比定點數字快,但這並不意味著我們傾向使用浮點數,浮點數會存在一定程度的精度損失,因為在IEEE-754標準中,並沒有任何辦法將

⼗進位制數

準確地存⼊硬體,它們只能使⽤⼀個⼤概的數字。

在某些金融領域,更多是在科學計算領域,程式對於精度的要求可能是嚴格的,我們就需要定長資料型別。

對於定點數來說,我們需要在資料庫系統實現,基本思路就是你將這個值作為

varchar

型別來儲存,即⽤⼈類實際可讀的值的形式來表示,接著,透過⼀些元資料來表示,這⾥是⼩數點,那⾥是精度範圍,接著另外⼀邊是四舍五⼊資訊。這些東⻄都要放在tuple⾥⾯,並且它是該位元組陣列的⼀部分。

大資料值

當我們想要儲存的東⻄因為體積太⼤⽽⽆法放在⼀個單個page,我們需要面對這個情況。

大多數DBMS不允許一個tuple超過單個頁面的大小,基於b-tree的特點,我們的page中儲存的tuple數至少要大於等於2,否則tree就退化為一個連結串列了。要儲存大於單個page的值,DBMS使用單獨的溢位儲存頁。

有兩種解決方法:溢位頁儲存和外部檔案儲存。

溢位頁儲存

⼤多數情況下,在整個表中或者是整個資料庫中,⼀個page的體積是被固定大小的。如果我們所要儲存的東⻄沒辦法儲存在⼀個單個page下,可以透過overflow page來解決這個問題。

如圖所示,假設在我們的tuple中,屬性d的值⽆法放在這個page中,我們透過⼀個指標來指向儲存了我們想要資料的那個overflow page,這就像是另⼀個record id,透過page number和slot id來告訴我們該去哪⾥找到我們需要 的那個資料。

1資料庫儲存(disk storage)

如果我們現在有⼀個查詢,想要將這個屬性值作為我們輸出的⼀部分,我們就必須根據這個指標,找到這個page,從它上⾯把資料拷⻉下來,並⽣成⼀個輸出結果。

如果我們存放的資料在這個overflow page 還是存不下,那麼就透過overflow page指標來指向某些其他東⻄,例如,某些其他page。我們可以將它們連結在⼀起,以此來⽣成我們想要的輸出結果。

可能不同的資料庫對 overflow page 的命名不一樣,但原理就是這樣的。

為了避免一些不必要的麻煩,比如故障恢復,我們不會像slot page那樣使用overflow page,overflow page幾乎是用來讀取的,除了存放slot page 溢位的資料的新增操作。(拿維基百科為例,你可以去更新⼀篇⽂章或者⼀個條⽬,但99。999%時候,⼈們只是讀取它)。

因此當我將它從磁碟中取出,並在存⼊記憶體後,可以將它進⾏壓縮,因為⼤部分時候,我都⽆須將它解壓,並對它進⾏更新。

外部檔案儲存

其基本思路就是,我們實際上不會將該屬性的正真的資料儲存在tuple內部,⽽是往⾥⾯儲存⼀個指標或者是⼀個⽂件路徑,它們指向能找到該資料的本地磁碟,或者⽹絡儲存,亦或是某些外部儲存裝置。就像我們在資料庫中儲存電子書的時候,往往是儲存一個電子書文字的檔案路徑 字串,而不是一個電子書內容字串。在這種情況下,你只能讀取資料,而不能update資料本身,只能進行重新替換。

如果我需要將它作為輸出結果,那需要去這些外部⽂件中查詢並讀取這些資料。

對於儲存選擇,我們可以根據資料大小進行邊界,比如任何⼩於256kb的東⻄,我們將它儲存在⼀個overflow page上,大於的則儲存在外部檔案。

當然這也不是完全的,對於許多⼿機應⽤來說,實際上最好將影象的縮圖儲存在資料庫系統中,因為從資料庫系統中讀取這些記錄要來得更快,因為它們已經將⽂件開啟,這樣就不⽤去根據指標在⽂件系統中查詢⽂件,然後使⽤f。open來開啟⽂件獲取資料流。

有時候需要根據效能和經濟角度進行考量。

系統 catalogs

DBMS在其內部catalogs 中儲存有關資料庫的元資料。

包括表、欄位、索引、檢視……

users,許可權許可;

靜態統計資料(用於SQL最佳化器的成本模型估算)。

幾乎每個DBMS都將資料庫的catalogs 儲存自己系統中。

圍繞tuples進行物件抽象

“bootstraping” catalog tables 的專門程式碼

在⼤部分時候,程式設計環境會提供給我們固定⻓度的資料:int ,long,char……,來幫助我們⾃⼰對那些可變⻓度的資料或者固定精度的東⻄進⾏實現。

很多資料庫系統都會將它們的Catalog⽤另⼀張表來儲存,將這些關於自己系統的表的所有元資料都存⼊這個表。內。不管你的資料庫系統是⽤什麼語⾔編寫的,⾥⾯都會透過某種底層⽅法來訪問catalog。

⼤部分資料庫系統會透過STANDARD INFORMATION_SCHEMA API把catalog暴露出來,在ANSI標準以及SQL標準中,它們定義了⼀種稱為INFORMATION_SCHEMA的東⻄,每個資料庫系統都必須⽀持它,以表示這是關於我的表的元資料。

SELECT * FRON INFDRMATION_SCHEMA。TABLES WHERE table_catalog = ‘

這樣我們可以獲取某張表的schema。

MySQL會在一個特定的資料夾記憶體放表schema資訊。

透過關注資料庫catalog,來跟蹤檢視我們的schema是什麼樣⼦。當我們去查詢以及構建索引時,會⽤到它,並決定我們應該怎麼做。

比如我們

select * from order where name = xx;

我們首先會從catalog中檢視order 有多少屬性以及其它需要的資訊。

儲存模型

通常,我們資料庫的模型有兩種:OLTP 聯機事務處理 和 OLAP 聯機分析處理。在OLTP中,我們會想去使⽤⾏儲存。然⽽在OLAP中,我們會想去使⽤列儲存。

前者通常用於網際網路的短小海量請求,它們讀取和修改的資料都比較少。

後者通常用於大資料分析或者機器學習等,他們的特點是請求較少,但是單次儲存和查詢的資料量巨大,且通常是針對某一型別(列)的資料的批次查詢,沒有或者很少更新操作。

最近有一些資料庫(TIDB,StarRocks,OceanBase)在向HTAP (混合事務分析處理)的方向發展,通常來說,這需要實現不同的引擎。

當我們談及tuple的時候表示我們想按照行的方式儲存而不是列的方式,書面地,被稱作:

N-ARY storage model

(NSM)。

DBMS為一個page裡的每個tuple連續地儲存其所有屬性,一般來說,他們需要被對齊(參考ps1對齊的意義),對於體積較⼤的物件,我們可以使⽤overflow page。這樣就能去訪問完整單個實體,拿到我們想要的 order tuple 或者user tuple 或者其它任何定義的東西。因此一行資料非常高效,跳那個page,找到那個tuple即可。

1資料庫儲存(disk storage)

如圖所示,假設我們有⼀個page,tuple中有⼀個header,這⾥我假設我們使⽤的是

slotted page

的格式。我們有header,接著user_id,name,age以及last_login。

只要當我們拿到了我們tuple中的最後⼀個屬性,意味著我們就拿到了該tuple的所有其他資料。所有東⻄都是連續排列的。

假設我要進⾏⼀次查詢,我想根據給定的⽤戶名拿到所有的賬號資訊,可以根據索引來進⾏查詢,關於索引,後面會介紹,這是個比較複雜的東西。但無論透過什麼方式,基本上來講,資料庫會告訴我們,我們想要tuple所在的

page id

slot number

我們會根據page id將tuple所在的page載入到記憶體,然後就可以根據slot number 從記憶體中找到tuple。所以,讓⼀個tuple的所有資料連續地放在⼀起是讀取資料時最有效的⽅式。

插入動作也是一樣的。我們需要將插⼊的資料連續地放在⼀起,然後找到⼀個空閒slot,將所有資料⼀次性寫⼊,接著將它刷⼊磁碟,並記錄⽇志。

總結:

資料庫是按照page來組織資料的,有⼏種不同的⽅式來跟蹤我們⽂件中的page,我們使用page directory的方式,接著,在這些page中,我們可以⽤不同的⽅式來儲存tuple。

然後討論瞭如何表示tuple內部的值,深⼊tuple的位元組序列中去,然後去分析儲存模型,也就是該如何在⼀張表內組織我們的tuple。

基於以上內容描述,你可以構建一個磁碟儲存管理器,這是實現你的資料庫的一個基礎,趕快開始吧。

ps

1:CPU在單位時間內處理的一組二進位制成為字,字的位數稱為字長。如果是32位CPU,字長為32位,也就是4位元組。一般,字長越大,CPU處理速度越快,比如64位CPU比32位CPU效率高。

32位CPU來說,CPU每次只能從記憶體中讀取4個位元組的資料,因此每次只能對4的倍數的地址進行讀取。

假設現在有一個int值,它的首地址並不是4的倍數,假設是0x2,因此它儲存在如圖所示的地址範圍:

1資料庫儲存(disk storage)

如圖所示,我們讀取該整數需要進行兩次讀取,並且需要對兩次的資料進行處理得到完整的int值。

1資料庫儲存(disk storage)

如果進行如上對齊,則只需要一次。事實上,我們所使用的高階開發語言的編譯器自動進行這樣的操作。