溫故而知新 能夠爲師矣node
Each tablespace consists of database pages with a default size of 16KB. The pages are grouped into extents of size 1MB (64 consecutive pages). The 「files」 inside a tablespace are called segments in InnoDB. Two segments are allocated for each index in InnoDB. One is for nonleaf nodes of the B-tree, the other is for the leaf nodes. Keeping the leaf nodes contiguous on disk enables better sequential I/O operations, because these leaf nodes contain the actual table data.sql
從示意圖能夠清晰的瞭解到MySQL的行數據Row都是存儲到數據頁Page上,每一個數據頁的大小爲16KB。而後64個數據頁進而組成一個區Extent,區又是段segment組成元素,一個索引擁有兩個段,其中leaf node seagment
存儲着邏輯上的行數據(主鍵索引),非主鍵索引存儲的是主鍵ID。數據庫
InnoDB使用了B+樹的索引模型。B+樹爲了維護索引的有序性,在插入新值的時候須要作必須的維護。若是在表尾插入,只需在記錄後面增長,要是增長的行在表中間,就須要挪動位置給插入的行騰出空間。更糟糕的是帶插入的數據頁Page已經滿了16KB,這時須要新申請一個新的數據頁,而後將部分數據挪過去。這個過程成爲也分裂。緩存
既然存在頁分裂,那麼固然也會存在頁合併。將利用率低的Page頁進行合併,頁分裂的逆過程。bash
不論是頁的分裂仍是合併,都會引發性能的損失。這裏就須要考慮主鍵是否必需要自增?主鍵自增的模式下,每次插入的新紀錄都是追加操做,都不涉及其它記錄的挪動,不會觸發葉子節點的分裂。服務器
TiDB的存儲與SQL模型是沒有關係的,TiKV 沒有選擇直接向磁盤上寫數據,而是把數據保存在 RocksDB 中,具體的數據落地由 RocksDB 負責。全部能夠簡化TiKV的存儲模型爲:網絡
Regionmvc
對於一個 KV 系統,將數據分散在多臺機器上有兩種比較典型的方案:一種是按照 Key 作 Hash,根據 Hash 值選擇對應的存儲節點;另外一種是分 Range,某一段連續的 Key 都保存在一個存儲節點上。TiKV 選擇了第二種方式,將整個 Key-Value 空間分紅不少段,每一段是一系列連續的 Key,咱們將每一段叫作一個 Region,而且咱們會盡可能保持每一個 Region 中保存的數據不超過必定的大小(這個大小能夠配置,目前默認是 64mb)。每個 Region 均可以用 StartKey 到 EndKey 這樣一個左閉右開區間來描述。分佈式
儘管Region跟Page的概念很像,但須要注意的時候Region是鍵值對的存儲區,與關係型數據表沒有關係。Region做爲TiDB提供分佈式和高可用的核心工做單元,將數據劃分紅 Region 後會作兩件事:ide
那麼關係型的表是如何在TiKV中進行映射呢?定義個表t1,主鍵爲id,惟一索引name和普通索引age。
CREATE TABLE t1 {
id BIGINT PRIMARY KEY,
name VARCHAR(1024),
age BIGINT,
content BLOB,
UNIQUE(name),
INDEX(age),
};
-- 向t1中插入兩條數據
insert into t1 values(1, 「a」, 10, 「hello」);
insert into t1 values(2, 「b」, 12, 「world」);
複製代碼
上面的兩條數據就會映射成下面的鍵值對存儲到TiKV的Map中:
PK
t_11_1 -> (1, 「a」, 10, 「hello」)
t_11_2 -> (2, 「b」, 12, 「world」)
Unique Name
i_12_a -> 1
i_12_b -> 2
Index Age
i_13_10_1 -> nil
i_13_12_2 -> nil
複製代碼
由於 PK 具備惟一性,因此能夠用 t + Table ID + PK 來惟一表示一行數據,value 就是這行數據。對於 Unique 來講,也是具備惟一性的,因此用 i + Index ID + name 來表示,而 value 則是對應的 PK。若是兩個 name 相同,就會破壞惟一性約束。當咱們使用 Unique 來查詢的時候,會先找到對應的 PK,而後再經過 PK 找到對應的數據,這裏與MySQL的回表有點相似。
對於普通的 Index 來講,不須要惟一性約束,因此使用 i + Index ID + age + PK,而 value 爲空。由於 PK 必定是惟一的,因此兩行數據即便 age 同樣,也不會衝突。當咱們使用 Index 來查詢的時候,會先 seek 到第一個大於等於 i + Index ID + age 這個 key 的數據,而後看前綴是否匹配,若是匹配,則解碼出對應的 PK,再從 PK 拿到實際的數據。
從兩個流程圖能夠不難看出SQL的被執行的流程分爲:
那麼TiDB做爲分佈式數據庫,在SQL處理過程當中存在下面幾個難點:
READ UNCOMMITTED
事務中能夠讀到其餘事務未提交的修改,形成髒讀。
READ COMMITTED
事務未提交的修改對其它事務是不可見的,事務只會看到被提交的修改。
REPEATABLE READ
在同一事務中讀取的數據始終是一致的,就算讀取的數據有被其它事務提交過修改。
使用讀寫鎖實現
使用mvcc實現ERIALIZABLE 事務的執行按照串行執行。
引用表格總結一下始終事務隔離
TiKV 的事務採用的是 Percolator 模型。TiKV 的事務採用樂觀鎖,事務的執行過程當中,不會檢測寫寫衝突,只有在提交過程當中,纔會作衝突檢測,衝突的雙方中比較早完成提交的會寫入成功,另外一方會嘗試從新執行整個事務。TiKV也實現了MVCC。TiKV 的 MVCC 實現是經過在 Key 後面添加 Version 來實現,簡單來講,沒有 MVCC 以前,能夠把 TiKV 看作這樣的:
Key1 -> Value
Key2 -> Value
……
KeyN -> Value
複製代碼
有了 MVCC 以後,TiKV 的 Key 排列是這樣的:
Key1-Version3 -> Value
Key1-Version2 -> Value
Key1-Version1 -> Value
……
Key2-Version4 -> Value
Key2-Version3 -> Value
Key2-Version2 -> Value
Key2-Version1 -> Value
……
KeyN-Version2 -> Value
KeyN-Version1 -> Value
……
複製代碼
最左前綴原則
因爲覆蓋索引(查詢中索引已經覆蓋了查詢的需求,能夠直接提供結果不須要回表,稱之爲:覆蓋索引)能夠顯著的優化查詢性能,而且索引的維護也是有代價的。因此如何權衡就是個問題。
最左前綴原則:即最左優先,在檢索數據時從聯合索引的最左邊開始匹配,也能夠是字符串索引的最左邊的字符開始匹配。在創建聯合索引時將高頻的字段放置左側。
索引下推:(index condition pushdown) 索引遍歷過程當中,對索引中包含的字段先作判斷,直接過濾掉減小回表。
這裏留個坑,後面去填。 索引範圍計算簡介