1. 程式人生 > >Mysql綜述(1)資料是如何讀存的

Mysql綜述(1)資料是如何讀存的

引言

我們都知道,mysql中的索引,事務,鎖等都是作為開發人員要重點掌握的知識面,但要想掌握理解好這些知識卻並非易事。
其中原因之一就是這些概念都過於抽象,事實上如果都不懂mysql資料是以一種怎樣結構儲存的,就直接去學習索引等模組,如此理解起來自然是事倍功半的。

因此本文的目的有兩點:

  • 揭露資料儲存的格式
  • 說明Mysql是如何讀取資料

在正文開始之前要先明確一點,Mysql有很多儲存引擎,不同的儲存引擎對於資料的存放格式是不一樣的,目前Mysql的儲存引擎預設是InnoDB,因此本文主要以InnoDB的角度去講解。

行格式

我們經常會說往表中插入一條資料,實際上InnoDB資料儲存的基本單位其實就是一條資料。這行資料在磁碟上儲存的格式就叫做行格式。

InnoDB設計了4種行格式,分別是Compact、Redundant、Dynamic和Compressed行格式,接下來我們會重點講解Compact,同時它也是最常用的行格式。

COMPACT行格式

直接先看一張圖:

看圖說話,Compact行格式可以分為兩大塊:

  • 額外資訊
  • 真實資料

所謂真實資料自然就是我們要存放的值,而額外資訊儲存的是對這行記錄的一些描述。

其中額外資訊包括變長欄位長度列表,NULL值列表,記錄頭資訊。

變長欄位長度列表

在Mysql有一些資料型別,比如VARCHAR(M)、TEXT等,它們是屬於支援變長的資料型別,實際使用的位元組數是不固定的。所以Mysql需要把這些型別的列實際使用了多少位元組數給記錄下來,記錄的地方就是在變長欄位長度列表。

在Compact行格式中,把所有變長欄位的真實資料佔用的位元組長度都存放在記錄的開頭部位,從而形成一個變長欄位長度列表,各變長欄位資料佔用的位元組數按照列的順序==逆序==存放。

舉個例子,我們建立個表

CREATE TABLE record_format_demo (
    ->     c1 VARCHAR(10),
    ->     c2 VARCHAR(10) NOT NULL,
    ->     c3 CHAR(10),
    ->     c4 VARCHAR(10)
    -> ) 

可以看到c1,c2,c4列都是變長的,此時我們插入一條資料

INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', 'cc', 'd')

我們假定內容佔用的位元組為

列名 儲存內容 佔用位元組(十六進位制表示)
c1 'aaaa' 0x04
c2 'bbb' 0x03
c4 'd' 0x01

所以這條記錄的儲存格式就為

可以看到變長欄位長度列表是逆序(c4->c2->c1)排放的。

因此要計算1個變長欄位到底佔用了多少空間要計算兩部分:

  • 真實資料佔用的空間
  • 記錄真實資料佔用空間所使用的位元組數

以列C1為例:

佔用位元組數='aaaa'(4位元組)+ '0x04'(1位元組)

NULL值列表

我們知道表中的某些列可能儲存NULL值,如果把這些NULL值都放到記錄的真實資料中儲存會很佔地方,所以Compact行格式把這些值為NULL的列統一管理起來,儲存到NULL值列表中。

每個允許儲存NULL的列對應一個二進位制位,二進位制位按照列的順序逆序排列,,二進位制位表示的意義如下:

  • 二進位制位的值為1時,代表該列的值為NULL。
  • 二進位制位的值為0時,代表該列的值不為NULL。

我們在來插入一條記錄

INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', null, null)

因此這條記錄的null值列表就是:

行格式就是:

可以看到二進位制110就是十進位制的6.

記錄頭資訊

記錄頭資訊,它是由固定的5個位元組組成。5個位元組也就是40個二進位制位,不同的位代表不同的意思。本文不會細講,在後續的文章中有涉及再說講解。

真實資料

真實資料除了c1、c2、c3、c4這幾個我們自己定義的列的資料以外,其實MySQL會為每個記錄預設的新增一些列(也稱為隱藏列),具體的列如下:

transaction_id和roll_pointer的作用將會在後面提及。

而row_id這個列只有在表沒有自定義主鍵並且Unique鍵的情況下才會新增,作為表的主鍵