前言
最近在學MySQL
禁灼,決定記錄一下,能寫多少寫多少轿曙,不定時更新弄捕,加油。
正文
分幾個部分來吧导帝,大致如下:
字符集與比較規(guī)則
行格式與數(shù)據(jù)頁
InnoDB
索引訪問方法與連接
explain 與 子查詢優(yōu)化
redo
與undo
日志MVCC
與 鎖
本文為第二部分 第二節(jié) 數(shù)據(jù)頁
上回說的單條記錄沒有挑戰(zhàn)守谓,下面開啟多條記錄的處理--數(shù)據(jù)頁
數(shù)據(jù)頁的秘密其實在前面我們說到的記錄頭的幾個屬性里面已經(jīng)說了一點了,比如分組您单、單鏈表斋荞、最小記錄、最大記錄虐秦、B+樹索引平酿、葉子節(jié)點等。
那么悦陋,讓我們繼續(xù)“脫衣服”~
數(shù)據(jù)頁結(jié)構(gòu)
名稱 | 中文名 | 占用空間大小 | 簡單描述 |
---|---|---|---|
File Header |
文件頭部 | 38字節(jié) | 頁的一些通用信息 |
Page Header |
頁面頭部 | 56字節(jié) | 數(shù)據(jù)頁專有的一些信息 |
Infimum + Supremum
|
最小記錄和最大記錄 | 26字節(jié) | 兩個虛擬的行記錄 |
User Records |
用戶記錄 | 不確定 | 實際存儲的行記錄內(nèi)容 |
Free Space |
空閑空間 | 不確定 | 頁中尚未使用的空間 |
Page Directory |
頁面目錄 | 不確定 | 頁中的某些記錄的相對位置 |
File Trailer |
文件尾部 | 8字節(jié) | 校驗頁是否完整 |
簡單的介紹一下這些屬性中的重要的東西
Infimum
+ Supremum
- 這個值位于整個頁面的第三部分
- 分別是最小記錄和最大記錄蜈彼,屬于MySQL為每個頁添加的
虛擬記錄
- 由五個字節(jié)的
記錄頭
和 八個字節(jié)的 值(分別是單詞Infimum
和Supremum
)組成 - 最小記錄的記錄頭中
heap_no
為0 - 最大記錄的記錄頭中
heap_no
為1 - 也就是說正式記錄中的
heap_no
屬性從2開始 - 最小記錄的record_type 是2
- 最大記錄的record_type 是3
- 最小記錄是頁中單鏈表的頭結(jié)點
- 最大記錄是頁中單鏈表的尾結(jié)點
Page Directory
- 這個頁目錄里面存的是一個一個的槽(
slot
) - 每個槽指向組內(nèi)最大記錄的地址偏移量(我理解為頁內(nèi)偏移量)
- 這個數(shù)據(jù)結(jié)構(gòu)是數(shù)組,按主鍵值從小到大排列
- 這種結(jié)構(gòu)注定了查詢最快的方式是二分法俺驶,時間復(fù)雜度O(lgN)
-
頁分裂
(前面說過) 時會增加一個槽
User Records
和 Free Space
- 完全空閑的頁是沒有
User Records
部分的 - 插入數(shù)據(jù)時幸逆,從
Free Space
分配空間給User Records
,直到Free Space
沒有空間或空間不夠分配新的記錄,這時需要申請新的頁
Page Header
名稱 | 占用空間大小 | 描述 |
---|---|---|
PAGE_N_DIR_SLOTS |
2字節(jié) | 在頁目錄中的槽數(shù)量 |
PAGE_HEAP_TOP |
2字節(jié) | 還未使用的空間最小地址秉颗,也就是說從該地址之后就是Free Space |
PAGE_N_HEAP |
2字節(jié) | 本頁中的記錄的數(shù)量(包括最小和最大記錄以及標記為刪除的記錄) |
PAGE_FREE |
2字節(jié) | 第一個已經(jīng)標記為刪除的記錄地址(各個已刪除的記錄通過next_record也會組成一個單鏈表痢毒,這個單鏈表中的記錄可以被重新利用) |
PAGE_GARBAGE |
2字節(jié) | 已刪除記錄占用的字節(jié)數(shù) |
PAGE_LAST_INSERT |
2字節(jié) | 最后插入記錄的位置 |
PAGE_DIRECTION |
2字節(jié) | 記錄插入的方向 |
PAGE_N_DIRECTION |
2字節(jié) | 一個方向連續(xù)插入的記錄數(shù)量 |
PAGE_N_RECS |
2字節(jié) | 該頁中記錄的數(shù)量(不包括最小和最大記錄以及被標記為刪除的記錄) |
PAGE_MAX_TRX_ID |
8字節(jié) | 修改當前頁的最大事務(wù)ID,該值僅在二級索引中定義 |
PAGE_LEVEL |
2字節(jié) | 當前頁在B+樹中所處的層級 |
PAGE_INDEX_ID |
8字節(jié) | 索引ID蚕甥,表示當前頁屬于哪個索引 |
PAGE_BTR_SEG_LEAF |
10字節(jié) | B+樹葉子段的頭部信息哪替,僅在B+樹的Root頁定義 |
PAGE_BTR_SEG_TOP |
10字節(jié) | B+樹非葉子段的頭部信息,僅在B+樹的Root頁定義 |
1.PAGE_GARBAGE
- 在頁面空間不夠時菇怀,會嘗試將所需空間與這個值比較凭舶,如果夠,那么將記錄移到臨時表中爱沟,再重新插回來(記錄逐條新增是不會產(chǎn)生碎片空間的)帅霜,但很明顯,這很耗性能
-
PAGE_BTR_SEG_LEAF
和PAGE_BTR_SEG_TOP
- 后面會說到段的概念呼伸,一個索引會有兩個段身冀,一個葉子節(jié)點段,一個非葉子節(jié)點段括享,這兩個屬性分別代表一個
Segment Header
搂根,代表了哪個表空間哪個頁面的哪個INODE Entry
(表空間號 + 頁面號 + 偏移量值)
File Header
名稱 | 占用空間大小 | 描述 |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM |
4字節(jié) | 頁的校驗和(checksum值) |
FIL_PAGE_OFFSET |
4字節(jié) | 頁號 |
FIL_PAGE_PREV |
4字節(jié) | 上一個頁的頁號 |
FIL_PAGE_NEXT |
4字節(jié) | 下一個頁的頁號 |
FIL_PAGE_LSN |
8字節(jié) | 頁面被最后修改時對應(yīng)的日志序列位置(英文名是:Log Sequence Number) |
FIL_PAGE_TYPE |
2字節(jié) | 該頁的類型 |
FIL_PAGE_FILE_FLUSH_LSN |
8字節(jié) | 僅在系統(tǒng)表空間的一個頁中定義,代表文件至少被刷新到了對應(yīng)的LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID |
4字節(jié) | 頁屬于哪個表空間 |
這個屬性里面的值就說三個:
FIL_PAGE_OFFSET
- 每個表空間的頁號唯一铃辖,四個字節(jié)足夠用了
-
FIL_PAGE_PREV
和FIL_PAGE_NEXT
- 上一頁和下一頁剩愧,誒喲,這不是雙向鏈表啊娇斩,那所有的頁加起來組成了一個雙向鏈表哇仁卷,好玩吧~
FIL_PAGE_TYPE
類型名稱 | 十六進制 | 描述 |
---|---|---|
FIL_PAGE_TYPE_ALLOCATED |
0x0000 | 最新分配,還沒使用 |
FIL_PAGE_UNDO_LOG |
0x0002 | Undo日志頁 |
FIL_PAGE_INODE |
0x0003 | 段信息節(jié)點 |
FIL_PAGE_IBUF_FREE_LIST |
0x0004 | Insert Buffer空閑列表 |
FIL_PAGE_IBUF_BITMAP |
0x0005 | Insert Buffer位圖 |
FIL_PAGE_TYPE_SYS |
0x0006 | 系統(tǒng)頁 |
FIL_PAGE_TYPE_TRX_SYS |
0x0007 | 事務(wù)系統(tǒng)數(shù)據(jù) |
FIL_PAGE_TYPE_FSP_HDR |
0x0008 | 表空間頭部信息 |
FIL_PAGE_TYPE_XDES |
0x0009 | 擴展描述頁 |
FIL_PAGE_TYPE_BLOB |
0x000A | BLOB頁 |
FIL_PAGE_INDEX |
0x45BF | 索引頁犬第,也就是我們所說的數(shù)據(jù)頁 |
現(xiàn)在只需要看這最后一個索引頁锦积,又稱數(shù)據(jù)頁(跟InnoDB
的特性有關(guān))
屬性介紹了一堆,還是不知道怎么查歉嗓,舉個栗子
- 假設(shè)一條查詢語句定位到了這個頁面
- 先將條件中的列(加深為
col
)與值(假設(shè)為x
)拎出來丰介,二分法定位在哪個組。
- 假設(shè)10個槽遥椿,(0 + 9)/2 = 4, 將第四個槽的條件列的值拿出來跟
x
比較基矮,如果x
大,那就從5~9的槽中繼續(xù)二分找冠场;如果x
小, 那就從0~4的槽中繼續(xù)二分; - 直到前后兩個槽相差為1家浇,那記錄就在那個大的槽里面,又每個槽其實存的是組內(nèi)最大記錄碴裙,那前一個槽對應(yīng)記錄的下一個節(jié)點就是目標槽對應(yīng)組中的最小值钢悲,順著單鏈表往后一個一個比就完事了点额,每組最多八條記錄,這速度還是很快的莺琳。
沒明白就多看兩遍~