探究InnoDB Compact行格式背后

?目錄

一、InnoDB 行格式數據準備

二、COMPACT行格式整體說明

三、記錄的額外信息

(一)變長字段長度列表

數據結構

存儲過程

讀取過程

變長字段長度列表存儲示例

(二)NULL 值位圖

數據結構

存儲過程

讀取過程

NULL 值位圖示例說明

(三)行頭信息

基本定義分析

案例分析

四、隱藏列

(一)基本說明

(二)主鍵的選擇順序說明

(三)案例分析

五、記錄真實數據

主要參考和學習來源


干貨分享,感謝您的閱讀!

先分享一個真實的案例:某大型電商平臺在一次促銷活動中遭遇了數據庫性能瓶頸,通過優化 InnoDB 的行格式,他們將查詢性能提升了30%,存儲成本降低了20%。這不僅幫助他們順利度過了高峰期,還大大提升了用戶體驗。

  • 查詢性能提升:通過選擇適當的行格式(如 Compact 或 Dynamic),可以減少存儲開銷和提升數據訪問速度,從而加快查詢響應時間。
  • 存儲成本降低:壓縮行格式(如 Compressed)可以顯著減少磁盤空間的使用,特別是在處理大量冗長字符串或重復數據時。

想象一下,你正在設計一個需要處理海量數據的應用,從用戶信息到交易記錄,每一行數據的存儲方式都會直接影響到你的系統響應速度和存儲成本。那么,如何選擇最合適的行格式來最大化性能和效率呢?

本次我們聚焦 InnoDB 行格式,理解它們是如何在幕后悄悄發揮作用的。行格式的設計反映了數據庫設計者在權衡性能、存儲和兼容性時的決策。到現在為止一共設計了4種不同類型的行格式 ,分別是 Compact 、 Redundant 、Dynamic 和 Compressed 行格式,隨著時間的推移,他們可能會設計出更多的行格式,但是不管怎么變,在原理上大體都是相同的。

我們本次主要針對Compact? InnoDB 行格式進行分析理解。

一、InnoDB 行格式數據準備

在 MySQL 中,數據是以記錄為單位插入到表中的,而這些記錄在磁盤上的存放方式,就是我們所說的“行格式”或者“記錄格式”。

首先,我們來看一下如何在創建或修改表時指定行格式。我們可以使用 CREATE TABLEALTER TABLE 語句來指定行格式。其語法如下:

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

假設我們在名為 xiaohaizi 的數據庫中創建一個名為 record_format_demo 的表,并指定它的行格式為 Compact,同時設置字符集為 ASCII(ASCII 字符集只包括空格、標點符號、數字、大小寫字母和一些不可見字符,所以我們的漢字是不能存到這個表里的)。如下所示:

向這個表中插入兩條記錄,并查看插入結果:

在實際應用中,選擇合適的行格式可以顯著提升數據庫的性能和存儲效率。例如,對于讀多寫少的場景,Compressed 行格式可能是一個不錯的選擇,而對于寫操作頻繁的場景,Compact 行格式可能會更合適。因各原理上大體都是相同,所以我們下面針對Compact進行理解。

二、COMPACT行格式整體說明

Compact 行格式適用于大多數通用場景,尤其是需要高效存儲和讀取的小型至中型表。它提供了良好的性能和平衡的存儲效率,是 InnoDB 存儲引擎中的默認選擇。

Compact 行格式在物理存儲上采用以下結構:

  • 行頭信息:用于存儲事務信息和回滾指針,占用 5 個字節。
  • NULL 值位圖:用于標識哪些列是 NULL 值,每個列對應 1 個 bit。
  • 變長字段長度列表:緊跟在 NULL 值位圖之后,記錄變長字段的長度信息。
  • 隱藏列:每行有 6 個字節用于兩個隱藏的系統列,包括事務 ID 和回滾指針。
  • 實際數據:存儲實際的數據值,緊湊排列。

三、記錄的額外信息

(一)變長字段長度列表

在 InnoDB 存儲引擎的 Compact 行格式中,變長字段長度列表用于存儲變長字段的長度信息,比如VARCHAR(M) 、 VARBINARY(M) 、各種 TEXT 類型,各種 BLOB 類 型。通過這種方式,Compact 行格式能夠高效地管理和存儲變長字段的數據。

由于變長字段的長度是不固定的,InnoDB 需要一種方式來記錄和讀取這些字段的實際長度,以便正確地存取數據。

數據結構

每個變長字段占用 1 到 2 個字節:長度小于 255 字節的字段使用 1 個字節來存儲長度信息,而長度等于或大于 255 字節的字段使用 2 個字節來存儲長度信息。

具體來說:

如果字段的長度小于 255 字節,則使用 1 個字節表示其長度。

如果字段的長度大于或等于 255 字節,則使用 2 個字節表示其長度。

存儲過程

  1. 計算每個變長字段的實際長度:對于每個變長字段,計算其實際長度。
  2. 根據長度決定字節數:如果長度小于 255,則使用 1 個字節存儲長度;否則,使用 2 個字節存儲長度。
  3. 存儲長度信息:將長度信息按順序存儲在變長字段長度列表中。
  4. 存儲實際數據:緊跟在變長字段長度列表之后存儲實際的數據值。

讀取過程

  1. 讀取變長字段長度列表:首先讀取變長字段長度列表,獲取每個變長字段的長度信息。
  2. 根據長度信息讀取數據:根據變長字段長度列表中的長度信息,準確定位和讀取每個變長字段的實際數據值。

變長字段長度列表存儲示例

針對之前創建的 compact_format_demo 表和插入的數據進行分析:

  • 針對第一條插入的數據 'aaaa', 'bbb', 'cc', 'd':
    • c1 字段值為 'aaaa',長度為 4(占用 1 個字節表示長度)。
    • c2 字段值為 'bbb',長度為 3(占用 1 個字節表示長度)。
    • c3 字段值為 'cc',長度為 2(占用 1 個字節表示長度)。
    • c4 字段值為 'd',長度為 1(占用 1 個字節表示長度)。
  • 針對第二條插入的數據 'eeee', 'fff', NULL, NULL':
    • c1 字段值為 'eeee',長度為 4(占用 1 個字節表示長度)。
    • c2 字段值為 'fff',長度為 3(占用 1 個字節表示長度)。
    • c3 字段為 NULL,不需要額外的長度信息。
    • c4 字段為 NULL,不需要額外的長度信息。

變長字段長度列表是按照字段順序緊跟在 NULL 值位圖之后存儲的。

  • 對于第一條記錄,長度列表為 [4][3][2][1],占用了 4 個字節。
  • 對于第二條記錄,長度列表為 [4][3],占用了 2 個字節。

總的長度列表占用了 6 個字節。

(二)NULL 值位圖

在 InnoDB 存儲引擎的 Compact 行格式中,NULL 值位圖用于標識每個字段是否為 NULL 值。在 InnoDB 存儲引擎中,NULL 值不占用實際的存儲空間,因此需要一種方式來標識哪些字段是 NULL,以便在讀取數據時正確處理這些字段。

數據結構

  • 每個字段占用 1 個 bit:位圖中的每個 bit 對應一列,用于標識該列是否為 NULL 值。
  • 位圖中的 bit 排列順序:按照字段在表中的順序依次排列,從左到右。

存儲過程

  1. 遍歷每個字段:對于每個字段,檢查其是否為 NULL 值。
  2. 設置對應位圖中的 bit:如果字段為 NULL 值,則將對應位圖中的 bit 設置為 1;否則,將其設置為 0。
  3. 位圖的實際存儲:位圖中的 bit 按照字段的順序依次存儲,每個 bit 占用 1 位。

讀取過程

  1. 讀取 NULL 值位圖:首先讀取 NULL 值位圖,獲取每個字段是否為 NULL 值的信息。
  2. 根據位圖讀取數據:根據位圖中的信息,準確讀取每個字段的數據值。如果對應位圖中的 bit 為 1,則表示該字段為 NULL 值;否則,讀取實際的數據值。

NULL 值位圖示例說明

還是針對之前創建的 compact_format_demo 表和插入的數據進行分析:

  • 對于第一條插入的數據 ('aaaa', 'bbb', 'cc', 'd'):

    • c1 字段的值為 'aaaa',不是 NULL 值。
    • c2 字段的值為 'bbb',不是 NULL 值。
    • c3 字段的值為 'cc',不是 NULL 值。
    • c4 字段的值為 'd',不是 NULL 值。
    • NULL 值位圖為 [0][0][0][0],表示所有字段均不為 NULL。
  • 對于第二條插入的數據 ('eeee', 'fff', NULL, NULL):

    • c1 字段的值為 'eeee',不是 NULL 值。
    • c2 字段的值為 'fff',不是 NULL 值。
    • c3 字段的值為 NULL,是 NULL 值。
    • c4 字段的值為 NULL,是 NULL 值。
    • NULL 值位圖為 [0][0][1][1],表示 c3c4 字段為 NULL,而 c1c2 字段不為 NULL。

(三)行頭信息

在 InnoDB 存儲引擎中,每個記錄都有一個記錄頭信息,它由固定的 5 個字節(40 個二進制位)組成。這 5 個字節中的每一位都有特定的含義,描述了記錄的一些重要信息。

基本定義分析

每個記錄的開頭有一個記錄頭信息,這些信息包含了對記錄的描述和控制。以下是每個二進制位代表的詳細信息:

  1. 預留位1(1 bit):該位暫時未被使用。

  2. 預留位2(1 bit):該位暫時未被使用。

  3. delete_mask(1 bit):標記該記錄是否被刪除。如果被刪除,則該位為 1;否則為 0。

  4. min_rec_mask(1 bit):B+樹的每層非葉子節點中的最小記錄都會添加該標記。如果是最小記錄,則該位為 1;否則為 0。

  5. n_owned(4 bits):表示當前記錄擁有的記錄數。使用 4 個 bits 來表示,可以表示的最大值為 15。

  6. heap_no(13 bits):表示當前記錄在記錄堆中的位置信息。使用 13 個 bits 來表示,可以表示的最大值為 8191。

  7. record_type(3 bits):表示當前記錄的類型。0:普通記錄。1:B+樹非葉子節點記錄。2:最小記錄。3:最大記錄。

  8. next_record(16 bits):表示下一條記錄相對于當前記錄的位置。使用 16 個 bits 來表示,可以表示的最大值為 65535。

這些記錄頭信息的二進制位提供了有關記錄的詳細描述,包括了是否被刪除、記錄的擁有數量、位置信息等。理解這些信息有助于更好地理解 InnoDB 存儲引擎中記錄的存儲和組織方式,以及對數據庫的性能和功能的影響。

案例分析

我們來分析一下 compact_format_demo 表中插入的第二條記錄 ('eeee', 'fff', NULL, NULL)的記錄頭信息分析:

先整理理論依據:

  1. delete_mask:用于標記記錄是否被刪除。
  2. min_rec_mask:用于標記是否是 B+ 樹非葉子節點中的最小記錄。
  3. n_owned:表示當前記錄擁有的記錄數。
  4. heap_no:表示當前記錄在記錄堆中的位置信息。
  5. record_type:表示當前記錄的類型,包括普通記錄、B+ 樹非葉子節點記錄、最小記錄和最大記錄。
  6. next_record:表示下一條記錄相對于當前記錄的位置。

現在可以進行如下推斷:

  • 對于 delete_maskmin_rec_mask,根據描述,如果滿足描述條件則為 1,否則為 0。
  • 對于 n_owned,在這個例子中沒有其他相關的記錄,所以這個值應該是 0。
  • 對于 heap_no,插入的第二條記錄應該在記錄堆的第二個位置,因此其二進制表示應該是 00000000000010。
  • 對于 record_type,根據描述,這是一個普通記錄,所以這個值應該是 0。
  • 對于 next_record,因為這是最后一條記錄,所以下一條記錄的相對位置應該是 0。

綜上所述,我們可以得出插入的第二條記錄的記錄頭信息應該是:

delete_mask: 0
min_rec_mask: 0
n_owned: 0
heap_no: 2
record_type: 0
next_record: 0

四、隱藏列

(一)基本說明

了解記錄的真實數據以外,還有一些隱藏列由MySQL自動添加到每個記錄中,這些列包括:

  1. row_id:行ID,用于唯一標識一條記錄。在InnoDB表中,如果用戶沒有定義主鍵,也沒有定義Unique鍵,則InnoDB會為表默認添加一個名為row_id的隱藏列作為主鍵。這個列的存在意味著即使沒有顯式定義主鍵,每條記錄仍然有一個唯一的標識符。

  2. transaction_id:事務ID,用于標識執行此次數據操作的事務。每個事務都有一個唯一的事務ID,這有助于數據庫跟蹤和管理事務的執行順序,以及處理并發事務之間的沖突。

  3. roll_pointer:回滾指針,用于實現多版本并發控制(MVCC)機制。回滾指針記錄了事務開始時行的舊版本的位置,以便在需要時回滾事務或查詢歷史數據。

(二)主鍵的選擇順序說明

提及row_id涉及到主鍵的生成策略時,InnoDB表遵循一定的規則來確定主鍵的選擇順序。具體如下:

  1. 用戶自定義主鍵:首先,InnoDB會優先選擇用戶自定義的主鍵作為表的主鍵。如果用戶已經顯式地定義了一個列作為主鍵,那么這個列將被用作表的主鍵。

  2. Unique鍵作為主鍵:如果用戶沒有定義主鍵,但定義了一個Unique鍵(唯一索引),那么InnoDB會將這個Unique鍵作為表的主鍵。這樣做是為了確保每條記錄都有一個唯一的標識符。

  3. 默認主鍵(row_id):如果表中既沒有用戶自定義的主鍵,也沒有定義Unique鍵,那么InnoDB會為表默認添加一個名為row_id的隱藏列作為主鍵。這個列是InnoDB內部生成的,用于確保每條記錄都有一個唯一的標識符。

(三)案例分析

對于第二條插入的數據 ('eeee', 'fff', NULL, NULL):

  1. 事務ID:每個事務都有一個唯一的事務ID,表示執行此次數據操作的事務。對于第二條插入的記錄,我們假設事務ID為 T2。

  2. 回滾指針:回滾指針用于實現多版本并發控制(MVCC)機制,記錄了事務開始時行的舊版本的位置。對于第二條插入的記錄,我們假設回滾指針為 RP2。

因此,插入的第二條記錄的隱藏列值可能如下所示:

  • 事務ID:T2(占用 6 個字節)
  • 回滾指針:RP2(占用 6 個字節)

這些隱藏列的值是由InnoDB存儲引擎自動生成的,對于用戶來說是不可見的,支持事務管理和并發控制。

五、記錄真實數據

記錄的真實數據是指用戶自定義的列數據,即在表中定義的可見列的值。

compact_format_demo 表中,可見列包括 c1c2c3c4。對于第二條插入的記錄 ('eeee', 'fff', NULL, NULL),其真實數據如下:

  • c1:'eeee'
  • c2:'fff'
  • c3:NULL
  • c4:NULL

這些值是用戶插入的數據,它們對于數據庫來說是可見的,可以通過查詢操作檢索到。與隱藏列不同,這些數據由用戶直接提供,并且在數據庫中占據著特定的列位置。

因為表 record_format_demo 并沒有定義主鍵,所以 MySQL 服務器會為每條記錄增加上述的3個列。現在看一下加上 記錄的真實數據 的兩個記錄長什么樣吧:

看這個圖的時候我們需要注意幾點:

  1. 表 record_format_demo 使用的是 ascii 字符集,所以 0x61616161 就表示字符串 'aaaa' , 0x626262 就表 示字符串 'bbb' ,以此類推。
  2. 注意第1條記錄中 c3 列的值,它是 CHAR(10) 類型的,它實際存儲的字符串是: 'cc' ,而 ascii 字符集中 的字節表示是 '0x6363' ,雖然表示這個字符串只占用了2個字節,但整個 c3 列仍然占用了10個字節的空 間,除真實數據以外的8個字節的統統都用空格字符填充,空格字符在 ascii 字符集的表示就是 0x20 。
  3. 注意第2條記錄中 c3 和 c4 列的值都為 NULL ,它們被存儲在了前邊的 NULL值列表 處,在記錄的真實數據處 就不再冗余存儲,從而節省存儲空間。

主要參考和學習來源

《MySQL 是怎樣運行的:從根兒上理解 MySQL》

https://dev.mysql.com/doc/refman/5.7/en/

https://dev.mysql.com/doc/internals/en/?

http://www.orczhou.com/

https://blog.jcole.us/innodb/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35024.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35024.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35024.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL進階之路 | 高級篇】索引的聲明與使用

1. 索引的分類 MySQL的索引包括普通索引,唯一性索引,全文索引,單列索引和空間索引. 從功能邏輯上說,索引主要分為普通索引,唯一索引,主鍵索引和全文索引.按物理實現方式,索引可以分為聚簇索引…

蘋果電腦清理垃圾怎么清理 macbook怎么清理電腦垃圾文件 macos優化軟件 cleanmymac怎么使用

在選擇電腦時,不少人都會選擇擁有高性能和輕薄機身的mac。一開始,它確實如我們所期待的那樣健步如飛,然而,隨著時間的流逝,有沒有覺得您的Mac有時候像是需要一個好的春季大掃除一樣?隨著我們不斷使用電腦&a…

Lobe Chat openai claude

claude-3-5-sonnet-20240620 $ docker run -d -p 3210:3210 \-e OPENAI_API_KEYsk-xxxx \-e OPENAI_PROXY_URLhttps://api-proxy.com/v1 \-e ACCESS_CODElobe66 \--name lobe-chat \lobehub/lobe-chatDocker 部署 更新 docker ps CONTAINER ID IMAGE …

1590. 【中山市第十二屆義務教育段學生信息學邀請賽】除法運算(divide)

時間限制: 1 s 空間限制: 256 MB 題目描述 Jimmy 開始學習除法啦!一開始他學習了余數為 0 的除法(也就是我們常說的整除),后來又學習了余數不為 0 的除法,所以 Jimmy 對被除數、除數、商、余數這些概念都已經了如指…

C語言學習步驟

C語言學習步驟 學習C語言是一個系統化的過程,以下是一些基本的步驟和建議: 1. 理解基礎概念:首先,了解編程的基本概念,比如變量常量、數據類型、指針、控制結構(順序語句、分支語句、循環語句)、…

神經網絡參數-----學習率(Learning Rate)

學習率 學習率是訓練神經網絡的重要超參數之一,它代表在每一次迭代中梯度向損失函數最優解移動的步長。它的大小決定網絡學習速度的快慢。在網絡訓練過程中,模型通過樣本數據給出預測值,計算代價函數并通過反向傳播來調整參數。重復上述過程…

Geoserver源碼解讀四 REST服務

文章目錄 文章目錄 一、概要 二、前置知識點-FreeMarker 三、前置知識點-AbstractHttpMessageConverter 3.1 描述 3.2 應用 四、前置知識點-AbstractDecorator 4.1描述 4.2 應用 五、工作空間查詢解讀 5.1 模板解讀 5.2 請求轉換器解讀 一、概要 關于geoserver的r…

zabbix-agent2啟動失敗報錯Unit zabbix-agent2.service entered failed state.

文章目錄 1,用systemctl status zabbix-agent2查看報錯狀態2,用journalctl -xe查看一下報錯日志3,再看一下zabbix的日志。4,錯誤修改5, 再次重啟zabbix-agent2 1,用systemctl status zabbix-agent2查看報錯…

高考季-計算機相關專業與所學核心課程介紹以及高考報考學校推薦

計算機相關專業通常包括計算機科學與技術、軟件工程、信息安全、網絡工程、人工智能等。以下是對這些專業的詳細介紹、所學課程內容以及一些推薦的學校和專業。 1. 計算機科學與技術 專業介紹 計算機科學與技術是研究計算機系統及其相關技術的學科,包括計算機硬件…

ref與reactive

在Vue 3中,ref 和 reactive 是兩種用于創建響應式狀態的API。它們在實現方式和使用場景上有所不同。下面是對 ref 和 reactive 的深度解析: 1. ref 解析 ref 用于創建一個單一的響應式引用,可以用來包裹基本類型(如字符串、數字…

Word如何在頁眉中插入和刪除橫線

你平常是否遇見到Word的頁眉中有一條橫線,怎么也刪不了!!! 今天劉小生分享如何在頁眉中插入和刪除橫線,我們一起操練起來吧! 1、Word頁眉插入橫線 選擇【插入】-【頁眉頁腳】,在“頁眉頁腳”…

00_Python核心編程

Python入門 一 Python初識 1 Python的歷史 Python的歷史python是蟒蛇的含義python是一種解釋型的,面向對象的,帶有動態語義的高級程序設計語言. python是一種使你在編程時能夠保持自己的風格的程序設計語言,你不用費什么勁就可以實現你想要的功能,并且編寫的程序清晰易懂. …

ArcGIS Pro SDK (五)內容 5 元數據

ArcGIS Pro SDK (五)內容 5 收藏夾 目錄 ArcGIS Pro SDK (五)內容 5 收藏夾1 獲取其 IMetadata 接口2 獲取項目的元數據:獲取XML3 設置項目的元數據:設置XML項4 檢查元數據是否可以編輯:可以編輯…

可靠性評估的概念和流程

可靠性評估的概念和流程 可靠性評估是系統工程中的一項重要任務,它旨在確定系統的可靠性和預期的運行時間,以便進行設計優化和維護決策。其概念和流程通常涉及以下幾個關鍵要素: 可靠性模型: 可靠性模型是描述系統或組件性能的…

常見的排序算法【總結】

目錄 排序的基本概念與分類排序的穩定性內排序與外排序簡單排序冒泡排序時間復雜度: O ( n 2 ) O(n^2) O(n2) 簡單選擇排序排序原理:時間復雜度: O ( n 2 ) O(n^2) O(n2) 插入排序排序原理:時間復雜度: O ( n 2 ) O(n^…

晶方科技:臺積電吃飽,封裝迎春?

半導體產業鏈掀起漲價潮,先進封裝迎接利好。 這里我們來聊國內先進封裝企業——晶方科技。 近期,由于產能供不應求,臺積電決定上調先進封裝產品價格,還表示訂單已經排到2026年。 大哥吃不下了,剩下的訂單全都是空間。…

主線程和子線程

主線程 當Java程序啟動時,一個線程會立刻運行,該線程通常叫做程序的主線程(main thread),即main方法對應的線程,它是程序開始時就執行的。 Java應用程序會有一個main方法,是作為某個類的方法出…

JDK 23:Loom改進版發布

1.新版 Loom EA 改進虛擬線程中的監視器(同步方法) Project Loom 發布了新的搶先體驗版本(23-loom4-102 - 2024/5/31)。改進了對象監視器實現,可以防止虛擬線程在以下情況下固定其載體線程: 當進入同步方法/語句時發生阻塞&…

問題-python-爬蟲無法爬取外網資源問題(python爬蟲)

方法一: 這個報錯通過關掉梯子就能解決,目前不清楚具體原理。 后續了解具體原理了,我會在這篇文章上更新具體分析—— 方法二: 也可以把這個東西打開,但是用完建議關掉。

python無法安裝scipy怎么辦

python安裝scipy時出現以下錯誤&#xff1a; from scipy.misc import imread Traceback (most recent call last):File "D:/Pyproject/qq_Spider/create_cloud.py", line 14, in <module>from scipy.misc import imread ModuleNotFoundError: No module named …