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