今日格言:讓一切迴歸原點,迴歸最初的爲何。mysql
本篇講解 Mysql 的主鍵問題,從爲何的角度來了解 Mysql 主鍵相關的知識,並拓展到主鍵的生成方案問題。不再怕被問到 Mysql 時只知道 CRUD 了。算法
如下廢話連篇,能夠直接跳過到下一節。sql
「信息是用來消除隨機不定性的東西」(香農)。人經過得到、識別天然界和社會的不一樣信息來區別不一樣事物,得以認識和改造世界。數據是反映客觀事物屬性的記錄,是信息的具體表現形式。數據通過加工處理以後,就成爲信息;而信息須要通過數字化轉變成數據才能存儲和傳輸。數據庫就是用於存儲數據記錄的。既已如此,記錄即是具備肯定性(相對)的信息,其肯定性即惟一性。咱們得出第一條緣由:mongodb
1.數據記錄需具備惟一性數據庫
世界是由客觀存在及其關係組成的。數據是數字化和模型化的存在關係。數據除了自己的描述價值外,其價值還在於其相互關聯性。爲實現關聯的準確性,數據須要有對外相互關聯的標識。因此體如今數據存儲上,主鍵的第二做用,也是存在的第二因素即:c#
2.數據須要關聯數據結構
數據用於描述客觀實在的,自己沒有意義。只有在根據主觀需求組織以後,經過必定方式知足人認識事物的過程才具備了意義。因此數據須要被檢索,被組織。則主鍵第三個做用:併發
3.數據庫底層索引用於檢索數據所需分佈式
這個問題的點在長上。那短比長有什麼優點?(嘿嘿嘿,內涵)—— 短不佔空間。但這麼點磁盤空間相對整個數據量來講微不足道,並且咱們通常不怎麼用到主鍵列。那麼緣由應該在快上,並且和原始數據關係不大。以此天然得出和索引相關,並且和索引讀取相關。那麼爲何長主鍵在索引中會影響性能?性能
上面是 Innodb 的索引數據結構。左邊是聚簇索引,經過主鍵定位數據記錄。右邊是二級索引,對列數據作索引,經過列數據查找數據主鍵。若是經過二級索引查詢數據,流程如圖上所示,先從二級索引樹上搜索到主鍵,而後在聚簇索引上經過主鍵搜索到數據行。其中二級索引的葉子節點是直接存儲的主鍵值,而不是主鍵指針。因此若是主鍵太長,一個二級索引樹所能存儲的索引記錄就會變少,這樣在有限的索引緩衝中,須要讀取磁盤的次數就會變多,因此性能就會降低。
InnoDB 使用聚簇索引,如上圖所示,數據記錄自己被存於主索引(一顆 B+Tree)的葉子節點上。這就要求同一個葉子節點內(大小爲一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,所以每當有一條新的記錄插入時,MySQL 會根據其主鍵將其插入適當的節點和位置,若是頁面達到裝載因子(InnoDB 默認爲 15/16),則開闢一個新的頁(節點)。
若是表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。這樣就會造成一個緊湊的索引結構,近似順序填滿。因爲每次插入時也不須要移動已有數據,所以效率很高,也不會增長不少開銷在維護索引上,以下圖左側所示。不然因爲每次插入主鍵的值近似於隨機,所以每次新記錄都要被插到現有索引頁的中間某個位置,MySQL 不得不爲了將新記錄插到合適位置而移動數據,以下圖右側所示,這樣就形成了必定的開銷。因爲此,Mysql 爲維護索引可能須要頻繁的刷新緩衝,增長了方法磁盤 IO 的次數,並且時常須要對索引結構進行重組織。
業務 Key,即便用具備業務意義的 id 做爲 Key,好比使用訂單流水號做爲訂單表的主鍵 Key。邏輯 Key,即無關業務的 Key,按某種規則生成 Key,如自增 Key。
通常狀況下,咱們都使用 Mysql 的自增 ID,來做爲表的主鍵,這樣簡單,並且從上面講到的來看,性能也是最好的。可是在分庫分表的狀況狀況下,自增 ID 則不能知足需求。咱們能夠來看看不一樣數據庫生成 ID 的方式,也看一些分佈式 ID 生成方案。利於咱們思考甚至實現本身的分佈式 ID 生成服務。
Mysql 在內存中維護一個自增計數器,每次訪問 auto-increment 計數器的時候, InnoDB 都會加上一個名爲AUTO-INC 鎖直到該語句結束(注意鎖只持有到語句結束,不是事務結束)。AUTO-INC 鎖是一個特殊的表級別的鎖,用來提高包含 auto_increment 列的併發插入性。
在分佈式的狀況下,其實能夠獨立一個服務和數據庫來作 id 生成,依舊依賴 Mysql 的表 id 自增能力來爲第三方服務統一輩子成 id。爲性能考慮能夠不一樣業務使用不一樣的表。
Mongodb 爲防止主鍵衝突,設計了一個 ObjectId 做爲主鍵 id。它由一個 12 字節的十六進制數字組成,其中包含如下幾部分:
Time:時間戳。4 字節。秒級。
Machine:機器標識。3 字節。通常是機器主機名的散列值,這樣就確保了不一樣主機生成不一樣的機器 hash 值,確保在分佈式中不形成衝突,同一臺機器的值相同。
PID:進程 ID。2 字節。上面的 Machine 是爲了確保在不一樣機器產生的 objectId 不衝突,而 pid 就是爲了在同一臺機器不一樣的 mongodb 進程產生的 objectId 不衝突。
INC:自增計數器。3 字節。前面的九個字節保證了一秒內不一樣機器不一樣進程生成的 objectId 不衝突,自增計數器,用來確保在同一秒內產生的 objectId 也不會發現衝突,容許 256 的 3 次方等於 16777216 條記錄的惟一性。
Cassandra 使用下面規則生成一個惟一的 id:time + MAC + sequence
1位符號位 + 41位時間戳(毫秒級)+ 10位數據機器位 + 12位毫秒內的序列
。列式存儲
時間序列數據庫(TSDB)初識與選擇
十分鐘瞭解 Apache Druid
Apache Druid 底層存儲設計
Apache Druid 的集羣設計與工做流程
Mysql 大表問題和解決
想了解更多數據存儲相關知識,請關注個人公衆號。