一行數據是怎麼存儲在磁盤的?

MySQL物理數據模型

每一行數據都是放在數據頁,按數據頁爲單位把磁盤上的數據加載到內存的緩存頁裏來,也是按照頁爲單位,把緩存頁的數據刷入磁盤上的數據頁中。

表、行和字段是邏輯上的概念,而表空間、數據區和數據頁就是物理概念。表空間、數據頁這些東西,都對應到了MySQL在磁盤上的一些物理文件。

SQL語句僅指定查詢或更新哪個表的哪些數據,怎麼知道:

  • 這些數據在哪個表空間?
  • 哪個數據區?
  • 哪些數據頁?
  • 對應MySQL機器哪些磁盤文件?

爲什麼不直接更新磁盤數據?

來一個請求就直接對磁盤文件進行隨機讀寫,然後更新磁盤文件裏的數據,必然導致執行請求性能極差。因爲磁盤隨機讀寫性能最差,所以MySQL才設計瞭如此複雜的一套機制,通過內存裏更新數據,然後寫redo log及事務提交,後臺線程不定時刷新內存裏的數據到磁盤文件。

這樣每個更新請求,儘量就是更新內存,然後順序寫日誌文件。更新內存性能極高,然後順序寫磁盤上的日誌文件性能也高,因爲順序寫磁盤文件,他的性能要遠高於隨機讀寫磁盤文件。

數據頁的意義

執行update之類的SQL時,必然涉及到對數據更新,那此時對數據不是直接去更新磁盤文件,而是要把磁盤上的一些數據加載到內存裏來,然後對內存裏的數據進行更新,同時 寫redo log到磁盤。

難道每次都是把磁盤裏的一條數據加載到內存裏去更新,然後下次要更新別的數據時,再從磁盤裏加載另外一條數據到內存?

這樣每次都是一條條數據加載到內存裏更新,效率不高。所以innodb引入數據頁,即將數據組織成一頁頁的,每頁16K,然後每次加載磁盤數據到內存時,至少加載一頁甚至多頁數據:

假設執行:

update xxx set xxx=xxx where id=1

則此時會將id=1這條數據所在的一頁數據都加載到內存,這頁數據裏可能還包含id=2,id=3等數據。

更新完id=1的數據後,接着更新id=2的數據,那此時是不是就不用再讀取磁盤裏的數據了?因爲id=2本就和id=1同頁,之前這頁數據就已加載到內存,直接更新內存裏的數據頁中的id=2這條數據即可。

如下就是數據頁的意義,磁盤和內存間的數據交換通過數據頁來執行,包括內存裏更新後的髒數據,刷回磁盤時,也是至少一個數據頁刷回去。

我們一直在內存裏更新各種數據,當I/O線程把內存裏的髒數據刷到磁盤時,也是以數據頁爲單位刷回。

一行數據在磁盤上是如何存儲的?

對一個表,可指定其行存儲的格式,比如這裏用COMPACT格式:

CREATE TABLE table_name (columns) ROW_FORMAT=COMPACT ALTER TABLE table_name ROW_FORMAT=COMPACT

建表時,就可指定行存儲格式,後續也能修改。

COMPACT行存儲格式下,每行數據實際存儲時,格式如下:

變長字段的長度列表,null值列表,數據頭,column01的值,column02的值,column0n的值......

對於每行數據,存儲時都會有一些頭字段對這行數據進行描述,再放上這一行數據每一列具體值,這就是所謂的行格式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章