一、邏輯儲存結構
表空間(Tablespace):一個mysql例項,及一個資料庫例項,可以對應多個表空間(ibd檔案),用於儲存記錄,索引等資料。
段(Segment):分為資料段(Leaf node segment)、索引段(Non-leaf node segment)、回滾段(Rollback segment),InnoDB是索引組織表,資料段就是B+樹的葉子節點(Leaf node segment),索引段即為B+樹的非葉子節點(Non-leaf node segment)。段用來管理多個Extent(區)。
區(Extent):表空間的單元結構,每個區的大小為1M, 預設情況下,InnoDB儲存引擎頁大小為16k,即一個區中一共有64個連續的頁
頁(Page):頁是InnoDB儲存引擎磁碟管理的最小單元,每個頁大小預設為16K,為了保證頁的連續,InnoDB儲存引擎每次從磁碟申請4-5個區
行(Row):InnoDB儲存引擎資料是按行進行存放的,Trx_id:每次對某條記錄進行改動時,都會把對應的事務id賦值給這個trx_id隱藏列。Roll_pointer:每次對某條記錄進行改動時,都會把舊的版本寫入到undo日誌中,然後這個隱藏列就相當於一個指標,透過它可以找到該記錄修改前的資訊
二、整體架構
MySQL5.5 版本開始,預設使用 InnoDB 儲存引擎,它擅長事務處理,具有崩潰恢復特性,在日常開發中使用非常廣泛,下面是 InnoDB 架構圖,左側為記憶體架構,右側為磁碟架構。
三、記憶體結構
記憶體架構中主要分為:Buffer Poll(記憶體緩衝池)、Change Buffer()、LogBuffer()、Adaptive Hash Index()四個區。
3.1 Buffer Pool
緩衝池是主記憶體中的一個區域,裡面可以快取磁碟上經常操作的真實資料,在執行增刪改查操作時,先操作緩衝池中的資料,若緩衝池沒有資料,則從磁碟載入並快取,然後再以一定頻率重新整理到磁碟,從而減少磁碟IO,加快出來速度。緩衝池以Page頁為單位,底層採用連結串列資料結構管理Page,根據狀態可以將Page分為三種型別。
-
- free page:空閒Page,未被使用。
- clean page:被使用page,資料沒有被修改過。
- dirty page:髒頁,被使用page,資料被修改過,其中資料與磁碟上的資料產生了不一致。
3.2 Change Buffer
更改緩衝區,針對與非唯一二級索引頁,在執行DML語句時,如果這些資料Page沒有在Buffer Pool中,不會直接操作磁碟,而是將資料變更存在更改緩衝區Change Buffer中,在未來資料被讀取時,再將資料合併恢復到Buffer Pool中,再講合併後的資料重新整理到磁碟中。
Change Buffer的意義:與集聚索引不同,二級索引通常是非唯一的,並且以相對隨機的順序插入二級索引,同樣,刪除和更新都可能會影響索引樹中不相鄰的二級索引頁,如果每一次都操作磁碟,會造成大量的磁碟IO,有了Change Buffer之後,我們可以在緩衝池中進行合併處理,減少磁碟IO
3.3 Adaptive Hash index
自適應hash索引,InnoDB預設是不支援hash索引的,預設支援的是B+樹的索引。因為hash索引不支援範圍查詢,僅可以用來做值匹配查詢。但是自適應hash索引,用於最佳化對Buffer Pool資料的查詢。InnoDB儲存引擎會監控對錶上各項索引頁的查詢,如果觀察到hash索引可以提升速度,則建立hash索引,稱之為自適應hash索引。
自適應雜湊索引,無需人工干預,是系統根據情況自動完成。透過 innodb_adaptive_hash_index 引數可以配置自適應hash索引的開啟和關閉。
mysql> show variables like "%innodb_adaptive_hash_index%"; +----------------------------------+-------+ | Variable_name | Value | +----------------------------------+-------+ | innodb_adaptive_hash_index | ON | | innodb_adaptive_hash_index_parts | 8 | +----------------------------------+-------+ 2 rows in set (0.00 sec)
3.4 Log Buffer
日誌緩衝區,用來儲存要寫入到磁碟中的log日誌(redolog,undolog),預設大小為16M, 日誌緩衝區的日誌會定期重新整理到磁碟中,如果需要更新、插入或者刪除許多行的事務,增加日誌緩衝區的大小可以節省磁碟i/o
透過 innodb_log_buffer_size 引數可以檢視緩衝區大小
透過 innodb_flush_log_at_trx_commit 引數可以檢視重新整理到磁碟時機。這裡有0,1,2三個值:
-
-
- 0:每秒將日誌寫入並重新整理到磁碟一次。
- 1:日誌在每次事務提交時寫入並重新整理到磁碟。
- 2:日誌在每次事務提交後寫入,並每秒重新整理到磁碟一次。
-
mysql> show variables like "innodb_log_buffer_size"; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+ 1 row in set (0.00 sec) mysql> show variables like "%flush_log%"; +--------------------------------+-------+ | Variable_name | Value | +--------------------------------+-------+ | innodb_flush_log_at_timeout | 1 | | innodb_flush_log_at_trx_commit | 1 | +--------------------------------+-------+ 2 rows in set (0.00 sec)
四、磁碟架構
4.1 System Tablespace
在MySQL中,System Tablespace(系統表空間)是一個用於儲存系統表和一些特殊表的預設表空間。系統表空間包含了以下幾個重要的系統表:
-
- mysql.user:儲存了MySQL中的使用者和許可權資訊。
- mysql.db:儲存了所有資料庫的資訊。
- mysql.host:儲存了允許連線到MySQL伺服器的主機資訊。
- mysql.tables_priv:儲存了表級別的許可權資訊。
- mysql.columns_priv:儲存了列級別的許可權資訊。
系統表空間還包含其他系統表,用於儲存MySQL伺服器的配置和後設資料資訊。
系統表空間預設儲存在名為`ibdata1`的共享檔案中。這個檔案通常位於MySQL的資料目錄下。
要注意的是,在InnoDB儲存引擎中,除了系統表空間(System Tablespace),還存在一個叫做表空間檔案(Tablespaces)的概念。表空間檔案用於儲存使用者建立的表和索引。每個InnoDB表都會有一個對應的表空間檔案。
需要注意的是,有時候系統表空間的大小會超過預期,導致空間不足或效能問題。在這種情況下,可以考慮調整系統表空間的大小或進行其他最佳化措施以解決問題。
總結:系統表空間是MySQL中用於儲存系統表和特殊表的預設表空間,包含了一些重要的系統表,通常儲存在名為`ibdata1`的共享檔案中。
4.2 File-Per-Table Tablespace
在預設情況下,所有的InnoDB表共享一個系統表空間,即儲存在ibdata1
檔案中。而使用File-Per-Table Tablespace選項,每個InnoDB表都會有一個獨立的表空間檔案,位於資料目錄下。
File-Per-Table Tablespace的優點包括:
-
- 管理:每個表有自己的表空間檔案,方便管理和維護。可以更方便地備份、恢復或遷移單個表。
- 效能:每個表具有獨立的表空間檔案,可以在磁碟上更好地分佈和組織資料,提高效能和併發訪問的能力。
- 儲存空間:使用File-Per-Table Tablespace可以更有效地使用儲存空間。當有大量小表或經常進行刪除和重建表時,每個表的表空間檔案可以更好地管理空間,避免系統表空間的不斷增長。
File-Per-Table Tablespace的缺點和注意事項包括:
-
- 管理複雜性:每個表都會有一個獨立的表空間檔案,這可能增加了管理的複雜性,包括備份和維護的管理操作。
- 儲存和檔案系統:使用File-Per-Table Tablespace可能涉及更多的磁碟IO操作,並可能增加檔案系統的碎片化問題。
使用File-Per-Table Tablespace可以在建立表時進行配置或在現有表上進行更改。要在建立新表時啟用File-Per-Table Tablespace,可以在建立表的DDL語句中加上ENGINE=InnoDB
選項。要在已有表上啟用File-Per-Table Tablespace,可以使用MySQL的ALTER TABLE
語句並設定innodb_file_per_table
引數為ON。
總結:File-Per-Table Tablespace是MySQL InnoDB儲存引擎的一個選項,允許每個表使用單獨的表空間檔案儲存資料和索引。它提供了更靈活的管理、更好的效能和更高效的儲存空間利用率
4.3 General Tablespaces
General Tablespaces(通用表空間)是MySQL 5.7版本引入的一個功能,在InnoDB儲存引擎中提供了更靈活和更高階的表空間管理選項。
通用表空間允許將多個InnoDB表儲存在一個或多個共享表空間檔案中,而不是每個表都有自己的獨立表空間檔案(如File-Per-Table Tablespace中)。這些共享表空間檔案可以在執行時動態新增或刪除新的表。
通用表空間的優點包括:
-
- 簡化管理:使用通用表空間可以更方便地管理和維護多個表。可以將相關的表組織在同一個共享表空間中,便於備份、恢復和遷移。
- 空間效率:通用表空間可以更有效地使用儲存空間。多個表可以共享一個表空間檔案,避免了為每個表都建立單獨的表空間檔案的開銷。
- 高效能:由於多個表共享表空間檔案,可以提高磁碟IO操作的效率。此外,共享表空間可以利用預讀機制(預讀相鄰頁)來提高查詢效能。
使用通用表空間時,可以在建立表時指定TABLESPACE
子句來為表分配到指定的共享表空間,也可以使用ALTER TABLE
語句將現有表移動到共享表空間中。
建立通用表空間示例:
mysql> create tablespace my_test add datafile "my_test.ibd" engine=InnoDB; Query OK, 0 rows affected (0.01 sec)
建立使用通用表空間的表示例:
mysql> create table tablespace_test(id int) tablespace my_test; Query OK, 0 rows affected (0.03 sec)
說明1:此時MySQL就不會再給tablespace_test表建立單獨的表空間了,而是使用通用表空間my_test.ibd空間
將現有表移動到通用表空間語法示例:
ALTER TABLE table_name TABLESPACE tablespace_name;
說明2:`table_name`是要移動的表的名稱,`tablespace_name`是要移動到的表空間的名稱。
刪除通用表空間語法示例
ALTER TABLESPACE tablespace_name DROP DATAFILE '<path>/tablespace_file.ibd';
說明3:`tablespace_name`是要刪除的表空間的名稱,`<path>/tablespace_file.ibd`是要刪除的表空間檔案的路徑和檔名。
4.4 undo Tablespace
在MySQL中,"undo tablespace"(撤銷表空間)是用於儲存撤銷日誌資料的一種特殊型別的表空間。
撤銷日誌是 MySQL 中的一項重要功能,用於回滾或撤銷事務中所做的更改。當事務執行 UPDATE、DELETE 或 INSERT 操作時,撤銷日誌記錄了被修改或刪除的非聚集索引的舊值,以及 INSERT 操作插入的新記錄。這些撤銷日誌記錄儲存在名為 "undo log" 的資料結構中。
為了高效地管理和儲存撤銷日誌資料,MySQL引入了 "undo tablespace" 的概念。撤銷表空間是一個獨立於資料表空間的區域,用於儲存撤銷日誌資料。它可以包含一個或多個檔案,這些檔案具有固定大小(通常是小於等於1GB)和特定的命名約定,預設的是undo_001和undo_002
撤銷表空間的主要作用有以下幾個方面:
-
- 提供事務的回滾能力:如果一個事務需要回滾,MySQL可以使用撤銷表空間中的撤銷日誌來還原事務執行前的資料狀態。
- 支援併發事務:撤銷表空間使得多個事務可以同時進行,並提供了事務隔離級別的支援。
- 回收空間:當事務完成時,撤銷表空間中的撤銷日誌可以被清除,空間可以被重複使用。
撤銷表空間在MySQL的配置檔案(my.cnf或my.ini)中透過innodb_undo_directory
和innodb_undo_tablespaces
配置項進行設定。innodb_undo_directory
定義了撤銷表空間檔案的儲存目錄,而innodb_undo_tablespaces
指定了要使用的撤銷表空間檔案的數量。
總結:撤銷表空間是MySQL中用於儲存撤銷日誌資料的表空間,支援事務的回滾、併發事務和空間回收。
4.5 Temporary Tablespace
在MySQL中,臨時表空間(Temporary Tablespace)是用於儲存臨時表資料和臨時結果集的一種特殊型別的表空間。臨時表空間的作用是儲存臨時表的資料,這些臨時表通常是在查詢過程中建立的。這些臨時表可能包括臨時表名、中間結果集或者用於排序和聚合的臨時資料。
預設情況下,MySQL使用系統表空間(system tablespace)來儲存臨時表資料。但是,在高併發環境下,使用單個系統表空間可能會導致效能瓶頸。為了提高效能並最佳化系統資源的使用,MySQL引入了臨時表空間的概念。透過為臨時表資料分配獨立的臨時表空間,MySQL可以更好地管理和最佳化臨時表的建立和使用。臨時表空間可以在獨立的表空間檔案中儲存臨時表資料,這些檔案可以位於不同的儲存裝置上,從而分散了IO負載。
可以透過以下配置項來設定臨時表空間:既可以寫在MySQL配置檔案中也可以在MySQL互動介面上使用set 指令設定
-`tmp_table_size`:用於設定每個臨時表的記憶體大小。如果臨時表大小超過此值,則會將其儲存到臨時表空間中。
-`max_heap_table_size`:用於設定只在記憶體中儲存的臨時表的最大大小。
-`tmpdir`:用於設定臨時表空間的目錄。
使用臨時表空間可以提升查詢效能,減少對系統表空間的負載,並提供更好的系統擴充套件性和可維護性。
總結:臨時表空間是MySQL中用於儲存臨時表資料和臨時結果集的表空間。它可以提高查詢效能,並分散IO負載,提供更好的系統資源利用和擴充套件性。
4.6 Doublewrite Buffer Files
4.7 Redo Log
在MySQL中,Redo Log(重做日誌)是用於實現事務的永續性和恢復能力的關鍵元件之一。它記錄了發生在資料庫中的資料更改操作,以確保在系統崩潰或斷電時,能夠將未完成的事務重新應用到資料庫中,以保持資料的一致性。
Redo Log是迴圈寫入的,意味著當日志檔案寫滿後,會重新從開頭開始覆蓋之前的日誌。所有的修改操作都會先寫入到Redo Log,然後非同步地重新整理到磁碟上的資料檔案。這樣即使在寫操作還未重新整理到磁碟上的資料檔案時發生崩潰,透過Redo Log的回放可以重新執行未完成的事務,確保資料的永續性。
Redo Log是以邏輯方式記錄的,而不是物理方式。它記錄了事務引起的資料修改,而不是實際的資料變化。透過記錄這些邏輯操作,MySQL可以在恢復時重新執行所需的操作。
在MySQL中,Redo Log由兩個檔案組成,通常為`ib_logfile0`和`ib_logfile1`。這些檔案的大小由配置引數`innodb_log_file_size`控制,預設情況下為`48MB`。可以在MySQL配置檔案中進行修改。
使用Redo Log的一個重要注意事項是,寫入Redo Log會引起磁碟IO操作,因此對於事務密集型負載,合理調整Redo Log的大小和I/O效能是很重要的。過小的Redo Log可能導致頻繁的重新整理和IO延遲,而過大的Redo Log可能對記憶體和磁碟空間帶來負擔。
總結:Redo Log是MySQL中用於實現事務的永續性和恢復的關鍵元件,它記錄了資料的修改操作,保證在系統崩潰或斷電後,能夠重新應用未完成的事務。Redo Log由兩個檔案組成,透過迴圈寫入的方式記錄資料修改。合理調整Redo Log的大小和I/O效能對於資料庫效能和永續性是重要的。