深入理解Mysql中頁分裂、合并的問題
一、UUID作為主鍵
如果使用UUID作為主鍵,因?yàn)閁UID是隨機(jī)字符串,那么它在有序的B+tree是如何排序的。
1、UUID在B+Tree中的存儲(chǔ)方式
UUID的字節(jié)序比較
// UUID內(nèi)部表示為16字節(jié)的二進(jìn)制數(shù)據(jù) // 比較規(guī)則:從左到右按字節(jié)比較 // 示例UUID比較: UUID1: 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d UUID2: 6d5c5a5e-5c5a-4e5a-8d5a-5a5e5c5a5e5c // 比較過程: // 第一個(gè)字節(jié):0x1a vs 0x6d → UUID1 < UUID2 // 因?yàn)?0x1a = 26, 0x6d = 109 注意: UUID 視為連續(xù)的 16 個(gè)字節(jié), UUID1 的字節(jié)序 列(十六進(jìn)制):1a 2b 3c 4d 5e 6f 7a 8b 9c 0d 1e 2f 3a 4b 5c 6d 0x1a中前面0x表示16進(jìn)制。其實(shí)就基本上可以理解每個(gè)字符對比,從左到右依次對比。
如果是長度不同的,短的排在前面
2、UUID作為主鍵的性能問題
2.1 插入性能問題
比如B+tree中已經(jīng)存在一個(gè)字符是B的節(jié)點(diǎn),因?yàn)閁UID生成是隨機(jī)的可能生成了一個(gè)A, 可能生成了一個(gè)C,那么A就會(huì)插入到B的前面,前面的樹都排好的,A一插入就會(huì)導(dǎo)致樹結(jié)構(gòu) 需要重排。但是自增ID或者順序插入,不會(huì)影響B(tài)+tree的問題。
2.2 B+Tree頁分裂問題
1、順序?qū)懭? -- 假設(shè)B+Tree的葉子節(jié)點(diǎn)容量為3條記錄 -- 當(dāng)前數(shù)據(jù)頁狀態(tài): 頁1: [1, 2, 3] -- 已滿 頁2: [4, 5, 6] -- 已滿 頁3: [7, 8] -- 有空間 -- 插入新記錄:id = 9 -- 過程:直接追加到頁3 → [7, 8, 9] ? -- 無頁分裂,性能極佳
2、UUID的插入過程(隨機(jī)寫入)
-- 同樣的B+Tree,使用UUID主鍵 -- 當(dāng)前數(shù)據(jù)頁狀態(tài)(按UUID排序): 頁1: [uuid_a, uuid_c, uuid_f] -- 已滿 頁2: [uuid_h, uuid_m, uuid_p] -- 已滿 頁3: [uuid_r, uuid_z] -- 有空間 -- 插入新記錄:uuid_k(隨機(jī)生成) -- 需要找到插入位置:在uuid_h和uuid_m之間 -- 但頁2已滿!觸發(fā)頁分裂過程
二、使用UUID解決排序問題:
1、自定義有序UUID生成
// 前8字節(jié):當(dāng)前時(shí)間戳(毫秒)+ 后8字節(jié):隨機(jī)數(shù),確保同一毫秒內(nèi)的唯一性 long timestamp = System.currentTimeMillis(); bb.putLong(timestamp);
2、優(yōu)先使用自增ID 或 雪花算法(有序字符串)
3、MySQL 8.0的UUID_TO_BIN
小結(jié)
總結(jié):不用UUID, 就算是無需的字符串作為主鍵,或者字符串作為非主鍵索引,都會(huì)有同樣的問題,所以不是特殊場景,盡量不要使用字符串作索引或者保持字符串是有序的插入。
所以在主鍵選擇上(插入性能+防止頁分裂):自增ID > 雪花算法(有序且分布式唯一)> 有序UUID(平衡唯一性和性能) > UUID(隨機(jī))
三、Mysql刪除數(shù)據(jù)對頁的影響
1、刪除中間數(shù)據(jù)時(shí)的B+Tree變化(可能會(huì)導(dǎo)致頁合并)
-- 初始狀態(tài):B+Tree葉子節(jié)點(diǎn) 頁1: [1, 3, 5] -- 已用空間 100% 頁2: [7, 9, 11] -- 已用空間 100% 頁3: [13, 15] -- 已用空間 66% -- 刪除中間數(shù)據(jù):刪除記錄 7 頁2: [9, 11] -- 已用空間 66%,有剩余空間 -- 刪除不會(huì)導(dǎo)致分裂,反而可能觸發(fā)合并?。ó?dāng)頁的使用率低于50%時(shí),觸發(fā)頁合并)
2、InnoDB的實(shí)際對頁合并做了優(yōu)化機(jī)制
1、刪除操作的惰性處理 -- InnoDB不會(huì)立即進(jìn)行頁合并,而是: -- 1. 標(biāo)記記錄為已刪除(邏輯刪除) -- 2. 在后臺由purge線程清理 -- 3. 在合適時(shí)機(jī)進(jìn)行頁合并 -- 查看刪除狀態(tài) SHOW ENGINE INNODB STATUS; -- 在輸出中查找 "PHYSICAL DELETES" 和 "LOGICAL DELETES"
所以我們的業(yè)務(wù)表,最好是定義一個(gè)邏輯刪除字段:is_Deleted
到此這篇關(guān)于Mysql中頁分裂、合并的問題的文章就介紹到這了,更多相關(guān)mysql頁分裂合并內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql查看連接數(shù)和設(shè)置會(huì)話超時(shí)問題
這篇文章主要介紹了mysql查看連接數(shù)和設(shè)置會(huì)話超時(shí)問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
MySQL存儲(chǔ)過程和存儲(chǔ)函數(shù)的用法解讀
這篇文章主要介紹了MySQL存儲(chǔ)過程和存儲(chǔ)函數(shù)的用法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-09-09
MySql數(shù)據(jù)庫基礎(chǔ)之分組查詢詳解
這篇文章主要介紹了mysql按照時(shí)間分組查詢的語句,非常實(shí)用,sql語句簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09

