日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

一文讲清,MySQL数据库一行数据在磁盘上是怎么存储的?

發布時間:2025/3/15 数据库 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文讲清,MySQL数据库一行数据在磁盘上是怎么存储的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據庫給使用者最直觀的感覺,就是庫、表、行、字段,這些概念都是邏輯上的。前面我們深入講解了Buffer Pool的內部原理,它的基本存儲單位是默認大小為16K的頁。每頁都保存了一行一行的數據。我們按照數據頁為單位把磁盤上的數據加載到內存的緩存頁里來,也是按照頁為單位,把緩存頁的數據刷入磁盤的數據頁中。

而我們常常聽到數據頁、數據區、表空間這些名詞,其實這些名詞是物理層面上的概念。我們不經要問,庫、表、行、字段,這些邏輯上的概念是如何對應到物理層的概念上的呢?我們查詢一行數據,是如何找到條數據所在的數據頁的呢?

接下來,筆者用幾篇文章,講解下MySQL的表空間、數據區、數據頁這些概念,當大家明白搞明白這些東西后,就自然理解上面的問題了。

行格式

行格式即行記錄的物理存儲格式,決定了這張表數據的物理存儲方式,會影響crud性能。

指定行格式

CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名稱; ALTER?TABLE?表名?ROW_FORMAT=行格式名稱;

InnoDB 包含以下四種行格式

  • Compact

  • Redundant

  • Dynamic

  • Compressed

mysql5.7之前的版本使用的是compact行格式,5.7及以后的版本使用的是dynamic行格式。Compact和Dynamic應用較廣泛,compact是目前使用最多的一種,而dynamic是新版本默認的行記錄格式。

初識MySQL行數據存儲格式

我們這里就以Compact存儲格式來講解。

Compact行格式下,每行數據的存儲格式,大概是這樣的:

變長字段(記錄的長度)列表,null值列表,數據頭,col1的值,col2的值,col3的值......

Compact 中一條完整的記錄可以被分成'記錄的額外信息'和'記錄的真實數據' 兩部分,其他三種存儲存儲格式基本大同小異。

變長字段是如何存儲的?

MySQL中變長字段長度是不固定的,?比如VARCHAR(50),實際存儲的內容可能是"hello",也可能是“hello world"。

所以,我們要讀取這類數據字段,必須要知道它的長度。

比如一行數據,它的幾個字段為VARCHAR(10), VARCHAR(5)
,VARCHAR(20),CHAR(1),CHAR(1),插入一行數據:hello, ni, hao, a, b。

此時磁盤中存儲的行開頭的變長字段長度列表,必須存儲幾個變長字段的長度,需要注意的是,這里是逆序存儲的。

行數據存儲格式是這樣的:

0x03 0x02 0x05 null值列表 頭字段?hello, ni, hao,?a, b

NULL值列表

null值列表,說的就是一行數據里可能有的字段是選填的,值可以是null。比如name字段,如果允許為null,那么實際存儲的時候,要標記出來。

為了節省存儲空間,MySQL設計的時候,使用二進制的bit位來存儲null值列表。

假如創建了一張表:

CREATE TABLE user ( name VARCHAR(10)NOT NULL,address VARCHAR(20),gender CHAR(1),job VARCHAR(30),school VARCHAR(50) )ROW_FORMAT = COMPACT;

user表5個字段,4個變長的,只有name是非NULL的,其他的4個字段都是可以為NULL的。

假如現在插入一行數據:zhangsan NULL M NULL Tsinghua,address和job是NULL,那么它在磁盤上是怎么存儲的?

NULL值列表,是這樣存儲的,你所有允許值為NULL的字段,都會有一個二進制的bit值,bit值為1說明是NULL,如果bit值為0說明不是NULL。

上面插入的那行數據,address、gender、job、school4個字段都允許為NULL,每個字段都會有一個bit位,其中address與job是NULL,所有4個bit位應該是:1010。

而且NULL值列表也是逆序存儲的,所以NULL值列表里是0101。

一般NULL值列表是8個bit位的倍數,如果不足8個bit位,則高位補0。

所以現在看來,行數據存儲格式是這樣的:

0x08 0x08?00000101 頭信息?col1的值,col2的值,col3的值......

數據頭以及真實數據

行數據的頭長度是固定的40bit,第一個bit和第二個bit,都是預留的,暫時沒有用到。

記錄頭信息詳細如下表所示,有的暫時沒有用到,可以暫時不用深究它。

現在再加上數據頭部分,上面的行存儲格式就變成這樣了,

0x08 0x08?00000101 0000000000000000000010000000000000011001 zhangsan M Tsinghua

剛開始先是變長字段的長度,用16進制表示,然后是NULL值列表,標識哪些值是NULL,接著是40bit的數據頭,最后是真實數據。

在讀取數據的時候,也會根據變長字段的長度,先讀取出長度為8的zhangsan。

然后發現第二個字段是NULL,就不用再讀了。

第三個字段是定長的1,就直接讀取出gender為M。

第四個字段是NULL,就不用再讀了。

第五個字段變長,長度是8,再讀取長度為8的Tsinghua。

然而,真正磁盤上存儲的時候,那些字符串就是直接存儲在磁盤上的嗎?

實際上,字符串都是根據數據庫指定的字符集編碼,進行編碼之后再存儲的,編碼后大概是這樣的:

0x08 0x08?00000101?0000000000000000000010000000000000011001?341324?134546 9342345

大家會看到上面,字符串和其他類型的數值最終都會根據數據庫字符集編碼,變成一些數字和符號存儲在磁盤上。

最后,在實際存儲一行數據的時候,MySQL還會給每條記錄,加入一些隱藏字段。如下表:

如果用戶沒有指定主鍵,且表中沒有Unique鍵時才會使用DB_ROW_ID作為主鍵。

最終,上面那條數據的存儲格式,變成這樣了:

0x08 0x08?00000101?0000000000000000000010000000000000011001?00000000034C(DB_ROW_ID)00000000036D(DB_TRX_ID) EA000010022B(DB_ROL_PTR) 341324?134546 9342345

到這里為止,我們基本把一行數據在磁盤上是如何存儲的講清楚了。

有道無術,術可成;有術無道,止于術

歡迎大家關注Java之道公眾號

好文章,我在看??

總結

以上是生活随笔為你收集整理的一文讲清,MySQL数据库一行数据在磁盘上是怎么存储的?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。