這篇文章是對知乎上如何自己實現乙個關係型資料庫的乙個嘗試性回答,後續會不斷更新。
對外資料模型為關係型資料庫,內部的實現主要分成兩大類,一類是disk-based,比如mysql,postgres,一類是memory based,後者包括memsql,sap haha,oceanbase。這裡說乙個disk-based的關係型資料庫涉及多少東西。
上世紀70/80年代記憶體不大,資料不能都放在記憶體裡,大部分資料都存在磁碟上,讀資料也需要從磁碟讀,然而讀寫磁碟太慢了,所以就在記憶體裡做了乙個buffer pool,將已經讀過的資料快取到buffer pool中,寫的時候也是寫到buffer pool中就返回,buffer pool的功能就是管理資料在磁碟和記憶體的移動。在buffer pool中資料的管理單位是page。page大小一般幾十kb。一般都可以配置。如果buffer pool中沒有空閒的page,就需要將某乙個page提出buffer pool,如果它是dirty page,就需要flush到磁碟,這裡又需要乙個lru演算法。乙個page包含多條記錄,page的格式需要設計用來支援變長字段。如果這時宕機了,buffer pool中的資料就丟了。這就需要redo log,將對資料的修改先寫到redo log中,然後寫buffer pool,然後返回給客戶端,隨後,buffer pool中的dirty page會被刷到資料檔案中(no force)。那麼重啟的時候,資料就能從redo log中恢復。redo log還沒刷完就刷資料到磁碟可以加快寫入速度,缺點就是恢復的時候需要回放undo log,回滾一些還沒有提交的事務的修改。寫log又分為邏輯log和物理log,還有物理邏輯log。簡單說邏輯log就是記錄操作,比如將某個值從1改成2.而物理log記錄具體到record的位置,例如某個page的某個record的某個field,原來的值是多少,新值是多少等。邏輯log的問題是併發情況下不太好恢復成一致。物理log對於某些操作比如create table又過於瑣碎,所以一般資料庫都採用混合的方式。為了跟蹤系統中各種操作的順序,這就需要為log分配id,記做lsn(log sequence number)。系統中記錄各種lsn,比如pagelsn, flushedlsn等等。為了加快宕機恢復速度,需要定期寫checkpoint,checkpoint就是乙個lsn。
以上acid裡的c和d有關。下面說a和i,即原子性和隔離性。
這兩個性質通過concurrency control來保證。隔離級別有很多種,最開始有4種,從低到高read uncommitted, read committed, repeatable read, serializable。serializable就是多個事務併發執行的結果和某種順序執行事務的結果相同。除了serializable,其他都有各種問題。比如repeatable read有幻讀問題(phantom),避免幻讀需要gap lock。read committed有幻讀和不可重複讀問題。後來又多了一些隔離級別,比如snapshot isolation,snapshot isolation也有write skew問題。早期,併發控制協議大多是基於兩階段鎖來做的(2pl),所以早期只有前面提到的四種隔離級別,後來,又出現一類併發控制協議,統稱為timestamp ordering,所以又多了snapshot isolation等隔離級別。關於隔離級別,可以看看這篇a critique of ansi sql isolation levels。2pl需要處理deadlock的問題。
timestamp ordering大體的思想就是認為事務之間衝突不大,不需要加鎖,只在commit的時候check是否有衝突。屬於一種樂觀鎖。
timestamp ordering具體來說包括多種,最常見的mvcc就是這類,還有一類叫做occ(optimistic concurrency control)。mvcc就是對於事務的每次更新都產生新的版本,使用時間戳做版本號。讀的時候可以讀指定版本或者讀最新的版本。幾乎主流資料庫都支援mvcc,因為mvcc讀寫互相不阻塞,讀效能高。mysql的回滾段就是用來儲存老的版本。mvcc需要有後台執行緒來做不再需要的版本的**工作。postgres的vacuum就是做這事的。occ和mvcc的區別是,occ協議中,事務的修改儲存在私有空間(比如客戶端),commit的時候再去檢測衝突,通常的做法是事務開始時看一下自己要修改的資料的最後一次修改的時間戳,提交的時候去check是否這個時間戳變大了,如果是,說明被別人改過了,衝突。衝突後可以回滾或者重試。
上面這些搞定了就實現了資料庫的核心,然後為了效能,需要index,通常有兩種,一種支援順序掃瞄b+tree,還有一種是hash index。單條讀適合用hash index,o(1)時間複雜度,順序掃瞄只適合用b+tree,o(logn)複雜度。然後,有些查詢只需要掃瞄索引就能得到結果,有些查詢直接掃瞄資料表就能得到結果,有些查詢可以走二級索引,通過二級索引找到資料表然後得到結果。。具體用哪種方式就是優化器的事了。
再外圍一些,關係型資料庫自然需要支援sql了,由sql變成最後可以執行的物理執行計畫中間又有很多步,首先sql通過詞法語法分析生成抽象語法樹,然後planner基於這棵樹生成邏輯執行計畫,邏輯執行計畫的生成通常涉及到等價謂詞重寫,子查詢消除等邏輯層面的優化技術,優化的目的當然是效能。比如等價謂詞重寫,用大於小於謂詞消除like,between .. and..等不能利用索引的謂詞。下一步是邏輯執行計畫生成物理執行計畫,物理執行計畫樹每個節點是乙個operator,operator的執行就是實實在在的操作,比如掃表的operator,filter opertor。乙個邏輯執行計畫通常可以有多個物理執行對應,選擇哪個就涉及到物理執行計畫優化,這裡涉及到經典的cost model,綜合考慮記憶體,cpu, i/o,網路等。最典型的,三表join,從左到右還是右到左,使用hash join,還是sort merge join等。關於查詢優化器可以參考資料庫查詢優化器的藝術:原理解析與sql效能優化
關係型資料庫 非關係型資料庫
關係型資料庫,是指採用了關係模型來組織資料的資料庫。關係模型是在1970年由ibm的研究員e.f.codd博士首先提出的,在之後的幾十年中,關係模型的概念得到了充分的發展並逐漸成為主流資料庫結構的主流模型。簡單來說,關係模型指的就是二維 模型,而乙個關係型資料庫就是由二維表及其之間的聯絡所組成的乙個...
關係型資料庫 非關係型資料庫
2019 02 25 20 38 36 關係型資料庫和非關係型資料的比較 一 關係型資料庫 關係型資料庫最典型的資料結構是表,由二維表及其之間的聯絡所組成的乙個資料組織 優點 1 易於維護 都是使用表結構,格式一致 2 使用方便 sql語言通用,可用於複雜查詢 3 複雜操作 支援sql,可用於乙個表...
關係型資料庫與非關係型資料庫
關係型資料庫與非關係型資料庫的區別 非關係型資料庫的優勢 1.效能 nosql是基於鍵值對的,可以想象成表中的主鍵和值的對應關係,而且不需要經過sql層的解析,所以效能非常高。2.可擴充套件性 同樣也是因為基於鍵值對,資料之間沒有耦合性,所以非常容易水平擴充套件。關係型資料庫的優勢 1.複雜查詢 可...