關係型數據庫(Relational Database)是一個偉大的發明,通常的數據庫的理論,大概會分紅如下三個部分。git
咱們發現,上面三個大的部分都是數據庫的理論知識,其實並無人告訴咱們怎麼來用代碼實現一個數據庫,由於科學家們認爲實現它並不重要,那是工程師要考慮的事情,Too Simple,科學家只負責搞出理論,反正咱們也不是科學家,那麼咱們就來作作工程師吧。github
工程師眼中的數據庫系統算法
既然是工程師,首先想到的就是如何來實現一個數據庫了,一個標準的數據庫大概主要會包含如下幾個大的模塊。sql
雖然看起來好像挺簡單,就是這麼三層,可是實際的數據庫是很是很是複雜的,除了這些之外還有不少其餘模塊,好比用戶權限管理,緩存模塊,日誌模塊,備份模塊等等等等,你們能夠仔細去看看innoDB的書籍或者innoDB的代碼,光一個binlog就特別麻煩。數據庫
其實要保存數據,搜索系統也能保存數據,並且檢索起來更快,而且二者的底層數據結構其實差異不是很大,但爲何用數據庫呢?由於數據庫的核心是可靠,這個可靠就是考數據庫的引擎層來保證的,完整的binlog記錄,崩潰後完整的重放機制,數據雙寫,內存數據定時刷新到磁盤,全部的這些都是爲了保證數據的可靠,不會丟失數據。編程
而上面說的每個功能,都能單獨的寫一篇長文,因此說要實現一個數據庫實際上是很麻煩的,由於爲了作到可靠,必然會有不少冗餘的數據或者冗餘的操做來保證可靠,但做爲一個成熟的產品,還須要考慮到產品的性能,因此,如何既可靠又性能優良,就變成了一個衡量數據庫好壞的標準,固然,在這兩點上,目前沒人能幹過oracle了。後端
數據庫如此之複雜,咱們如何對他進行瘦身 ,來實現一個最小的數據庫系統呢?咱們能夠從另一個角度想一想,就是咱們拿數據庫是幹什麼的?那就是存儲和查詢數據,若是這麼來想的話,就能簡單很多。緩存
首先,咱們知道數據庫最重要的功能就是存儲數據,那麼底層的存儲部分是不能少的,其次,存儲的數據要提供查詢功能,否則存了就沒意義了,這也是不能少的,第三,須要提供一個對外的接口能夠和用戶交互,否則就既不能存也不能查了。網絡
因此,一個最最基本的數據庫至少應該包含數據層,查詢層(引擎層)和UI(用戶接口)層三層,那麼咱們就用幾個簡單的文件來實現這三層,完成一個最小的數據庫吧。數據結構
數據庫的基本單位是列,再上一級的基本單位就是表了,並且咱們在建表的時候都會指定列的名稱,類型,長度這三個最基本的屬性,若是全部列都有這三個屬性,那麼其實咱們是知道每一行數據最多有多少字節的,因此,咱們能夠設定沒一行數據的長度都是定長的,那麼整個表的長度也是定長的了,這樣查詢的時候能夠根據行的長度進行快速定位數據,因此,咱們的最底層數據就是一個定長的表格了,每一列存儲的時候就像下面這樣,而後有個meta信息來存儲列的屬性
這個看上去很簡單吧?也容易實現吧,其實不少數據庫也基本上確實是這麼實現的,並不難理解吧?稍微注意一下的是每一列存儲的時候,每一個字段的前四個字節保存的是這個字段的實際長度,而後纔是字段的實際內容,若是長度小於建表時的設定長度,那麼有一部分空間是浪費掉的,雖然是浪費了,但仍是值得的,由於可讓查詢的時候省很多事。
這麼下來,每行記錄就是一個定長的,而一個數據庫的表就是一個二進制文件了,但僅僅是這樣仍是不夠的,由於這樣結構,不管什麼查詢都須要掃描全表,依次進行判斷,而咱們在建表的時候都會創建索引,爲了創建索引,咱們還得實現一個B+樹來存儲索引,而B+樹基本上是全部數據庫的索引保存的數據結構,這裏咱們也有實現,若是對B+樹感興趣,能夠看我以前的一篇文章,那篇有詳細的B+樹的實現方式,文章後有那篇文章的連接。
總之,數據底層咱們就用了一個定長的二進制文件和幾棵B+樹,再加上一個meta信息文件來實現了一個數據庫的底層數據層,很簡單哈,但基本上包括了數據庫真實的底層,雖然真正的數據庫比這複雜多了,但也跑不掉這幾個數據結構,整個看下來,數據層的數據結構大致上長這樣子。
固然,數據層實現完了之後,還須要對上提供幾個簡單的接口,好比
底層已經有了,接下來就是上面的查詢層(引擎層)了,這裏我沒用引擎兩個字,是由於最小數據庫的實現上,實在算不上一個引擎系統,咱們實現最簡單的基本查詢SQL(建表sql,插入數據sql,單表查詢sql)的解析,在實際中,SQL的解析是一個異常複雜的工程,涉及到語法分析,預處理,優化查詢等幾個大的部分,由於SQL實際上是一門編程語言,要解析一門編程語言,那麼編譯原理那一套基本上都會用獲得。
這裏咱們換條路子,由於只實現三種簡單的SQL語句,那麼咱們直接用正則和字符串的匹配來對SQL進行解析,解析完成之後變成一個個數據層的對外接口,建表和插入數據都比較簡單,解析了SQL之後直接調用上面的第一和第二接口就好了。
數據查詢的時候,對查詢SQL的WHERE以後的部分,用了個小算法,就是逆波蘭表達式來對WHERE以後的語句進行解析,變成一個棧結構來存儲查詢的內容,而後經過彈棧的方式一個一個調用接口三,而且對結果進行求交和求並的操做,最後獲得結果之後,再依次調用接口四獲取最後的結果,若是對逆波蘭表達式不瞭解,那麼請自行百度一下,很簡單的,主要用在對四則運算的優先級的解析中。
查詢層的輸入輸出很簡單,他對外實際上只提供一個接口。ExecSqlSentence( Sql ) string,都是字符串,輸入是一條條的sql語句,輸出是數據。
對於用戶的接口層就更加簡單了,咱們只須要提供一個TCP服務就好了,用;分號來分割每次用戶的輸入,也就是說,咱們telnet上咱們這個數據庫,而後輸入sql,數據庫就會返回數據了。
我在github上創建了一個新的工程叫SparrowSys,麻雀工程,意思很明顯,這是一個後端的麻雀,是最簡單的後端輪子,目前我也已經提交了一部分代碼,數據庫的尚未寫完,後面會補上的。
數據庫的部分在src下的SparrowDB裏面,很明顯的看到裏面有DataLayer,EngineLayer,NetLayer,對應的就是上面的三層,每層裏面有一到兩個文件,都很簡單,目前DataLayer基本完成了,後面會把EngineLayer和NetLayer補上,後面的文章會說說使用,utils文件夾中是一些公共的東西,後面的其餘輪子會用到的,好比B+樹就在utils裏面。
目前這個工程裏面東西很少,不建議看,後面我補全之後會說明,歡迎你們提交你的實現來代替個人。接受任何pull request。