Mysql 小主鍵,大問題

2022-03-17 12:02:45 字數 3739 閱讀 9458

今日格言:讓一切回歸原點,回歸最初的為什麼。

本篇講解 mysql 的主鍵問題,從為什麼的角度來了解 mysql 主鍵相關的知識,並拓展到主鍵的生成方案問題。再也不怕被問到 mysql 時只知道 crud 了。

資料記錄需具有唯一性(第一正規化)

資料需要關聯join

資料庫底層索引用於檢索資料所需

以下廢話連篇,可以直接跳過到下一節。

資訊是用來消除隨機不定性的東西」(夏農)。人通過獲得、識別自然界和社會的不同資訊來區別不同事物,得以認識和改造世界。資料是反映客觀事物屬性的記錄,是資訊的具體表現形式。資料經過加工處理之後,就成為資訊;而資訊需要經過數位化轉變成資料才能儲存和傳輸。資料庫就是用於儲存資料記錄的。既已如此,記錄便是具有確定性(相對)的資訊,其確定性即唯一性。我們得出第一條原因:

1.資料記錄需具有唯一性

世界是由客觀存在及其關係組成的。資料是數位化和模型化的存在關係。資料除了本身的描述價值外,其價值還在於其相互關聯性。為實現關聯的準確性,資料需要有對外相互關聯的標識。所以體現在資料儲存上,主鍵的第二作用,也是存在的第二因素即:

2.資料需要關聯

資料用於描述客觀實在的,本身沒有意義。只有在根據主觀需求組織之後,通過一定方式滿足人認識事物的過程才具有了意義。所以資料需要被檢索,被組織。則主鍵第三個作用:

3.資料庫底層索引用於檢索資料所需

這個問題的點在上。那有什麼優勢?(嘿嘿嘿,內涵)—— 短不佔空間。但這麼點磁碟空間相對整個資料量來說微不足道,而且我們一般不怎麼用到主鍵列。那麼原因應該在上,而且和原始資料關係不大。以此自然得出和索引相關,而且和索引讀取相關。那麼為什麼長主鍵在索引中會影響效能?

上面是 innodb 的索引資料結構。左邊是聚簇索引,通過主鍵定位資料記錄。右邊是二級索引,對列資料做索引,通過列資料查詢資料主鍵。如果通過二級索引查詢資料,流程如圖上所示,先從二級索引樹上搜尋到主鍵,然後在聚簇索引上通過主鍵搜尋到資料行。其中二級索引的葉子節點是直接儲存的主鍵值,而不是主鍵指標。所以如果主鍵太長,乙個二級索引樹所能儲存的索引記錄就會變少,這樣在有限的索引緩衝中,需要讀取磁碟的次數就會變多,所以效能就會下降。

innodb 使用聚簇索引,如上圖所示,資料記錄本身被存於主索引(一顆 b+tree)的葉子節點上。這就要求同乙個葉子節點內(大小為乙個記憶體頁或磁碟頁)的各條資料記錄按主鍵順序存放,因此每當有一條新的記錄插入時,mysql 會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(innodb 預設為 15/16),則開闢乙個新的頁(節點)。

如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序新增到當前索引節點的後續位置,當一頁寫滿,就會自動開闢乙個新的頁。這樣就會形成乙個緊湊的索引結構,近似順序填滿。由於每次插入時也不需要移動已有資料,因此效率很高,也不會增加很多開銷在維護索引上,如下圖左側所示。否則由於每次插入主鍵的值近似於隨機,因此每次新記錄都要被插到現有索引頁的中間某個位置,mysql 不得不為了將新記錄插到合適位置而移動資料,如下圖右側所示,這樣就造成了一定的開銷。由於此,mysql 為維護索引可能需要頻繁的重新整理緩衝,增加了方法磁碟 io 的次數,而且時常需要對索引結構進行重組織。

業務 key,即使用具有業務意義的 id 作為 key,比如使用訂單流水號作為訂單表的主鍵 key。邏輯 key,即無關業務的 key,按某種規則生成 key,如自增 key。

業務 key 的優點

業務 key 的缺點

邏輯 key 的優點

邏輯 key 缺點一般情況下,我們都使用 mysql 的自增 id,來作為表的主鍵,這樣簡單,而且從上面講到的來看,效能也是最好的。但是在分庫分表的情況情況下,自增 id 則不能滿足需求。我們可以來看看不同資料庫生成 id 的方式,也看一些分布式 id 生成方案。利於我們思考甚至實現自己的分布式 id 生成服務。

mysql 自增

mysql 在記憶體中維護乙個自增計數器,每次訪問 auto-increment 計數器的時候, innodb 都會加上乙個名為auto-inc 鎖直到該語句結束(注意鎖只持有到語句結束,不是事務結束)。auto-inc 鎖是乙個特殊的表級別的鎖,用來提公升包含 auto_increment 列的併發插入性。

在分布式的情況下,其實可以獨立乙個服務和資料庫來做 id 生成,依舊依賴 mysql 的表 id 自增能力來為第三方服務統一生成 id。為效能考慮可以不同業務使用不同的表。

mongodb objectid

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 timeuuid

cassandra 使用下面規則生成乙個唯一的 id:time + mac + sequence

zookeeper 自增:通過 zk 的自增機制實現。

redis 自增:通過 redis 的自增機制實現。

uuid:使用 uuid 字串作為 key。

snowflake 演算法:和 mongodb 的實現類似,1位符號位 + 41位時間戳(毫秒級)+ 10位資料機器位 + 12位毫秒內的序列

美團 leaf:同時實現了基於 mysql 自增(優化)和 snowflake 演算法的機制。

mysql:小主鍵,大問題

mysql大資料量問題與解決

你應該知道一些其他儲存——列式儲存

時間序列資料庫(tsdb)初識與選擇(influxdb、opentsdb、druid、elasticsearch對比)

十分鐘了解apache druid(集資料倉儲、時間序列、全文檢索於一體的儲存方案)

apache druid 底層儲存設計(列儲存與全文檢索)

apache druid 的集群設計與工作流程

小eval解決大問題 python

先說情況,今天學習做了一道把我堵了天的題,主要是每次輸出都是預設str,但我如果想輸入list,或者tuple呢?這個時候就需要eval。看案例 寫函式,判斷使用者傳入的物件 字串 列表 元組 長度是否大於5。def fun args inp input please input buzhuanh ...

strcat 小bug引起的大問題

在除錯stm32時,單步打斷點執行時,沒有問題,但是全速執行時,偶爾會跳過錯誤,偶爾也會跳轉hardfault 問題實在難找。最後定位在傳送資料的快取上,發現傳送快取部分除了應該有的資料之外,還有好多不 為0的值 也就是說,在棧上申請的記憶體,沒有經過初始化,就使用strcat來追加字串了 詳細查了...

mysql 主鍵問題處理

mysql的主鍵問題 mysql的兩種主鍵。primary key 和not null auto incriment 在建立mysql表時,給乙個字段新增了主鍵primary key 在insert資料時可以不用insert主鍵,mysql會自動新增0,但是在第二次insert時沒有填寫值mysql...