本節着重分析一下表空間,通過本節我們將清楚以下幾個問題:
1、什麼是表空間(Tablespace)?
2、InnoDB 存儲引擎有哪些表空間(Tablespace)?
3、InnoDB 存儲引擎中的表空間(Tablespace)有什麼用?
4、表空間(Tablespace)有哪些組成部分?及各個表空間的作用?
文章目錄
1、簡述
InnoDB 表空間(Tablespace)可以看做一個邏輯概念,InnoDB 把數據保存在表空間,本質上是一個或多個磁盤文件組成的虛擬文件系統。InnoDB 表空間不僅僅存儲了表和索引,它還保存了回滾日誌(redo log)、插入緩衝(insert buffer)、雙寫緩衝(doublewrite buffer)以及其他內部數據結構。
默認情況下InnoDB存儲引擎有一個共享表空間ibdata1,即所有數據都放在這個表空間內。如果我們配置了參數 innodb_file_per_table,則每張表內的數據可以單獨放到一個表空間內。其對應的存儲文件都放在 innodb_data_home_dir 指定的目錄下。
當啓用了 innodb_file_per_table 參數選項,需要注意的是,每張表的表空間內存放的只是數據、索引和插入緩衝,其它的數據,如撤銷(Undo)信息、系統事務信息、二次寫緩衝(double write buffer)等還是存放在原來的共享表空間內。這也就說明了另一個問題:即使在啓用了參數 innodb_file_per_table ,共享表空間還是會不斷地增加其大小。
2、InnoDB 邏輯存儲結構
從 InnoDB 邏輯存儲結構來看,所有的數據都被邏輯的存放在一個空間中,這個空間就叫做表空間(tablespace)。表空間有 段(segment)、區(extent)、頁(page)組成。
2.1、段(segment)
段(Segment)分爲索引段,數據段,回滾段等。其中索引段就是非葉子結點部分,而數據段就是葉子結點部分,回滾段用於數據的回滾和多版本控制。一個段包含256個區(256M大小)。
2.2、區(extent)
區是頁的集合,一個區包含64個連續的頁,默認大小爲 1MB (64*16K)。
2.3、頁(page)
頁是 InnoDB 管理的最小單位,常見的有 FSP_HDR,INODE, INDEX 等類型。所有頁的結構都是一樣的,分爲文件頭(前38字節),頁數據和文件尾(後8字節)。頁數據根據頁的類型不同而不一樣。
每個空間都分爲多個頁,通常每頁16 KiB。空間中的每個頁面都分配有一個32位整數頁碼,通常稱爲“偏移量”(offset),它實際上只是頁面與空間開頭的偏移量(對於多文件空間,不一定是文件的偏移量)。因此,頁面0位於文件偏移量0,頁面1位於文件偏移量16384,依此類推。 (InnoDB 的數據限制爲64TiB,這實際上是每個空間的限制,這主要是由於頁碼是32位整數與默認頁大小的組合: x 16 KiB = 64 TiB。)
如圖所示,每個page都有38個字節的FIL header,以及8個字節的FIL trailer(FIL是file的簡稱)。FIL header包含了一個表示page type的字段,這個字段用來確定這個page數據的結構。
FIL header和trailer示意圖如下所示:
FIL header和trailer包含以下結構:
-
checksum: 4個字節32位checksum保存在header中。
-
Offset: 頁面初始化後,頁面編號就存儲在header中。根據從文件中獲得的偏移量檢查從該字段讀取的頁碼是否與應該匹配的頁碼相符,這有助於指示讀取正確,並且此字段已初始化表示頁面已初始化。
-
Previous/Next Page: 指向此頁面類型的邏輯上一頁和下一頁的指針,被保存在header中。這允許建立頁面的雙向鏈接列表,並且它用於INDEX頁面以及同一級別的所有頁面。
-
page type: 頁面類型存儲在標題中。爲了解析其餘頁面數據,這是必需的。頁面被分配用於文件空間管理,範圍管理,事務系統,數據字典,撤消日誌,blob,當然還有索引(表數據)。
-
space ID: 保存在header中,space的32位整型唯一編號。
-
Old-style Checksum: 舊格式32位checksum被保存在header中,不過已經被廢棄,這塊空間被申明爲一些指針。
-
LSN: 頁的最後修改的64位日誌序列號(LSN)存儲在header中,而同一LSN的低32位存儲在尾部中。
3、表空間(Tablespace)分類
3.1、系統表空間
系統表空間是變更緩衝區的存儲區。如果在系統表空間中創建表,而不是在每個表文件或常規表空間中創建表,則它也可能包含表和索引數據。在以前的MySQL版本中,系統表空間包含InnoDB數據字典。在MySQL 8.0中,InnoDB將元數據存儲在MySQL數據字典中。在以前的MySQL版本中,系統表空間還包含doublewrite 緩衝區存儲區。自MySQL 8.0.20起,此存儲區位於單獨的 doublewrite 文件中。
系統表空間可以有一個或多個數據文件。默認情況下,在數據目錄中創建一個名爲 ibdata1 的系統表空間數據文件。系統表空間數據文件的大小和數量由 innodb_data_file_path 啓動項定義。
歸納一下,系統表空間包含 數據字典,雙寫緩衝,變更緩衝區、undo日誌,以及在系統表空間創建的表的數據和索引。
系統空間(space 0)在InnoDB中是特殊的,以固定頁碼分配的相當多頁面,以存儲對InnoDB操作至關重要的各種信息。由於系統空間是一個與其他空間一樣的空間,它的前三個頁面包括: FSP_HDR,IBUF_BITMAP 和 INODE頁。
3.1、獨佔表空間
獨立表空間就是每個表單獨創建一個 .ibd 文件,該文件存儲着該表的索引和數據。由 innodb_file_per_table 變量控制。禁用 innodb_file_per_table 會導致InnoDB在系統表空間中創建表。
innodb_file_per_table 設置可以在配置文件中指定,也可以在運行時使用 SET GLOBAL 語句進行配置。在運行時更改設置需要足夠的權限來設置全局系統變量
通過配置文件設置:
[mysqld]
innodb_file_per_table=ON
運行時設置:
mysql> SET GLOBAL innodb_file_per_table=ON;
3.1.1、獨佔表空間文件結構
InnoDB 表空間文件 .ibd 初始大小爲 96K,而InnoDB默認頁大小爲 16K,頁大小也可以通過 innodb_page_size 配置。在ibd文件中,0-16KB偏移量即爲0號數據頁,16KB-32KB的爲1號數據頁,以此類推。頁的頭尾除了一些元信息外,還有C hecksum 校驗值,這些校驗值在寫入磁盤前計算得到,當從磁盤中讀取時,重新計算校驗值並與數據頁中存儲的對比,如果發現不同,則會導致 MySQL 崩潰。
InnoDB頁分爲INDEX頁、Undo頁、系統頁,IBUF_BITMAP頁, INODE頁等多種。
- 第0頁是 FSP_HDR 頁,主要用於跟蹤表空間,空閒鏈表、碎片頁以及區等信息。
- 第1頁是 IBUF_BITMAP 頁,保存Change Buffer的位圖。
- 第2頁是 INODE 頁,用於存儲區和單獨分配的碎片頁信息,包括FULL、FREE、NOT_FULL 等頁列表的基礎結點信息,這些結點指向的是 FSP_HDR 頁中的項,用於記錄頁的使用情況,它們之間關係如下圖所示。
- 第3頁開始是索引頁 INDEX(B-tree node),從 0xc000(每頁16K) 開始,後面還有些分配的未使用的頁。
3.1.2、獨佔表空間優點
與共享表空間(例如系統表空間或常規表空間)相比,獨佔表空間具有以下優點。
1、使用獨佔表空間,刪除表後可以回收所佔的磁盤空間。如果使用共享表空間的話,刪除表後,共享表空間數據文件的大小不會縮小。
2、對駐留在共享表空間中的表進行 ALTER TABLE 操作可能會增加該表空間佔用的磁盤空間量。此類操作可能需要與表中的數據以及索引一樣多的額外空間。該空間不會像獨佔表空間那樣釋放佔用的磁盤。
3、在駐留在獨佔表空間的表上執行操作時,TRUNCATE TABLE性能更好。
4、可以在單獨的存儲設備上創建獨佔表空間數據文件,以進行I/O優化,空間管理或備份。
5、可以從另一個MySQL實例導入獨佔表空間中的表。
6、在獨佔表空間中創建的表支持與 DYNAMIC 和 COMPRESSED 行格式相關聯的功能,而系統表空間不支持這些功能。
7、當發生數據損壞,備份或二進制日誌不可用或無法重新啓動MySQL服務器實例時,存儲在獨佔表空間數據文件中的表可以節省時間並提高成功恢復的機會。
8、可以使用MySQL Enterprise Backup快速備份或還原在獨佔表空間中創建的表,而不會中斷其他InnoDB表的使用。這對於具有不同備份計劃的表或需要較少備份頻率的表很有用。
9、獨佔表空間允許通過監視表空間數據文件的大小來監視文件系統上的表大小。
10、當 innodb_flush_method 設置爲O_DIRECT時,常見的Linux文件系統不允許併發寫入單個文件,例如共享表空間數據文件。因此,結合使用此表時,可以使用獨佔表空間來提高性能。
11、共享表空間中的表的大小受64TB表空間大小限制。相比之下,每個表的每個文件表空間都有64TB的大小限制,這爲單個表的大小增加提供了足夠的空間。
3.1.3、獨佔表空間缺點
與共享表空間(例如系統表空間或常規表空間)相比,獨佔表空間具有以下缺點。
1、使用獨佔表空間,每個表可能有未使用的空間,只能由同一表的行使用,如果管理不當,則會浪費空間。
2、fsync 操作是對多個獨佔表空間數據文件而不是單個共享表空間數據文件執行的。由於fsync操作是針對每個文件的,因此無法合併多個表的寫操作,這可能導致fsync操作的總數增加。
3、mysqld 必須爲每個表文件空間保留一個打開的文件句柄,如果每個表文件空間中有許多表,則可能會影響性能。
4、每個表都有其自己的數據文件時,需要更多的文件描述符。
5、可能存在更多碎片,這可能會妨礙 DROP TABLE和表掃描性能。但是,如果管理碎片,則獨佔表空間可以提高這些操作的性能。
6、刪除駐留在獨佔表空間中的表時,將掃描緩衝池,對於大型緩衝池可能要花費幾秒鐘。使用寬泛的內部鎖定執行掃描,這可能會延遲其他操作。
7、innodb_autoextend_increment 變量定義了增量大小,用於在自動擴展共享表空間文件已滿時擴展其大小,該變量不適用於獨佔表空間文件,無論innodb_autoextend_increment 設置如何,該文件均會自動擴展。獨佔表空間的初始文件表擴展很小,此後擴展以4MB爲增量。
3.2、常規表空間
常規表空間是使用 CREATE TABLESPACE 語法創建的共享InnoDB表空間.
常規表空間提供了以下功能:
-
類似於系統表空間,常規表空間是共享表空間,可以存儲多個表的數據
-
常規表空間比獨佔表空間具有潛在的內存優勢。服務器在表空間的生存期內將表空間元數據保留在內存中。與獨佔表空間中的相同數量的表相比,常規表空間中的多個表元數據消耗的內存更少。
-
常規表空間數據文件可以放置在相對於MySQL數據目錄或獨立於MySQL數據目錄的目錄中,該目錄爲您提供了許多數據文件和獨佔表空間的存儲管理功能。與獨佔表空間一樣,將數據文件放置在MySQL數據目錄之外的功能使您可以分別管理關鍵表的性能,爲特定表設置RAID或DRBD或將表綁定到特定磁盤。
-
常規表空間支持所有錶行格式和相關功能。
-
TABLESPACE選項可與CREATE TABLE一起使用,以在常規表空間,獨佔表空間或系統表空間中創建表。
-
TABLESPACE選項可與ALTER TABLE一起使用,以在常規表空間,獨佔表空間和系統表空間之間移動表。以前,不可能將表從獨佔表空間移動到系統表空間。使用常規表空間功能,您現在可以這樣做。
3.2.1、創建常規表空間
常規表空間是使用CREATE TABLESPACE語法創建的。
CREATE TABLESPACE tablespace_name
[ADD DATAFILE 'file_name']
[FILE_BLOCK_SIZE = value]
[ENGINE [=] engine_name]
常規表空間可以在數據目錄中或在其外部創建。爲避免與隱式創建的獨佔表空間衝突,不支持在數據目錄下的子目錄中創建常規表空間。在數據目錄之外創建常規表空間時,該目錄必須存在並且在創建表空間之前InnoDB必須知道。要使InnoDB知道未知目錄,請將目錄添加到 innodb_directories 參數值。 innodb_directories 是隻讀的啓動選項。配置它需要重新啓動服務器。
示例:
1、在數據目錄中創建常規表空間:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
或
mysql> CREATE TABLESPACE `ts1` Engine=InnoDB;
從MySQL 8.0.14開始,ADD DATAFILE 子句是可選的,在此之前是必需的。如果在創建表空間時未指定ADD DATAFILE 子句,則會隱式創建具有唯一文件名的表空間數據文件。唯一文件名是128位UUID,格式爲五組十六進制數字,中間用破折號(aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeeeee)分隔。常規表空間數據文件包括.ibd 文件擴展名。在複製環境中,在主服務器上創建的數據文件名與在從屬服務器上創建的數據文件名不同。
2、在數據目錄之外的目錄中創建常規表空間:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE '/my/tablespace/directory/ts1.ibd' Engine=InnoDB;
您可以指定相對於數據目錄的路徑,只要表空間目錄不在數據目錄下即可。在此示例中,my_tablespace目錄與數據目錄處於同一級別:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE '../my_tablespace/ts1.ibd' Engine=InnoDB;
注意:ENGINE = InnoDB子句必須定義爲CREATE TABLESPACE語句的一部分,或者InnoDB必須定義爲默認存儲引擎(default_storage_engine = InnoDB)。
3.2.2、將表添加到常規表空間
創建InnoDB常規表空間後,可以使用 CREATE TABLE tbl_name … TABLESPACE [=] tablespace_name 或 ALTER TABLE tbl_name TABLESPACE [=] tablespace_name 將表添加到表空間,如以下示例所示:
CREATE TABLE:
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1;
ALTER TABLE:
mysql> ALTER TABLE t2 TABLESPACE ts1;
注意:在MySQL 5.7.24中棄用了將表分區添加到共享表空間的支持,在MySQL 8.0.13中不再支持。共享表空間包括InnoDB系統表空間和常規表空間。
3.2.3、常規表空間支持的行格式
常規表空間支持所有錶行格式(冗餘,緊湊,動態,壓縮:【REDUNDANT, COMPACT, DYNAMIC, COMPRESSED】),但要注意的是,由於物理頁大小不同,壓縮表和未壓縮表不能在同一常規表空間中共存。
要使常規表空間包含壓縮表(ROW_FORMAT = COMPRESSED),必須指定 FILE_BLOCK_SIZE,並且 FILE_BLOCK_SIZE 值必須是相對於 innodb_page_size 值的有效壓縮頁大小。另外,壓縮表的物理頁面大小(KEY_BLOCK_SIZE)必須等於 FILE_BLOCK_SIZE / 1024。例如,如果 innodb_page_size = 16KB 且 FILE_BLOCK_SIZE = 8K,則表的 KEY_BLOCK_SIZE 必須爲8。
下表顯示了允許的 innodb_page_size,FILE_BLOCK_SIZE 和 KEY_BLOCK_SIZE 組合。 FILE_BLOCK_SIZE 值也可以以字節爲單位指定。要確定給定FILE_BLOCK_SIZE的有效KEY_BLOCK_SIZE值,請將FILE_BLOCK_SIZE值除以1024。表壓縮不支持32K和64K InnoDB頁面大小。
3.2.4、常規表空間限制
1、生成的或現有的表空間無法更改爲常規表空間。
2、不支持創建臨時常規表空間。
3、常規表空間不支持臨時表。
4、與系統表空間類似,存儲在常規表空間中的表被刪除會在常規表空間 .ibd 數據文件內部創建可用空間,該空閒空間僅可用於新的InnoDB數據。獨佔表空間的空間不會釋放回操作系統。
此外,對駐留在共享表空間(常規表空間或系統表空間)中的表進行表複製ALTER TABLE操作可能會增加表空間使用的空間量。此類操作需要與表中的數據以及索引一樣多的額外空間。複製表ALTER TABLE操作所需的額外空間不會像釋放獨佔表空間那樣釋放回操作系統。
5、屬於常規表空間的表不支持ALTER TABLE … DISCARD TABLESPACE和ALTER TABLE … IMPORT TABLESPACE。
6、在MySQL 5.7.24中棄用了將表分區放置在常規表空間中的支持,在MySQL 8.0.13中已刪除。
7、在主服務器和從服務器位於同一主機上的複製環境中,不支持ADD DATAFILE子句,因爲它將導致主服務器和從服務器在同一位置創建同名的表空間,這不支持。但是,如果省略了ADD DATAFILE子句,則在數據目錄中創建表空間,並使用允許的唯一生成的文件名。
3.3、Undo 表空間
Undo 表空間包含 undo log,Undo 表空間是撤消日誌記錄的集合,其中包含有關如何通過事務撤消對聚集索引記錄的最新更改的信息。撤消日誌存在於撤消日誌段中,撤消日誌段中包含撤消日誌段。 innodb_rollback_segments 變量定義分配給每個撤消表空間的回滾段數。
初始化MySQL實例時,會創建兩個默認的Undo 表空間。默認的Undo 表空間是在初始化時創建的,以提供回滾段的位置,這些段必須存在才能接受SQL語句。至少需要兩個Undo 表空間才能支持Undo 表空間的自動截斷。
默認的Undo 表空間在 innodb_undo_directory 變量定義的位置中創建。如果未定義 innodb_undo_directory 變量,則會在數據目錄中創建默認的Undo 表空間。默認的Undo 表空間數據文件名爲 undo_001 和 undo_002。數據字典中定義的相應Undo 表空間名稱是 innodb_undo_001 和 innodb_undo_002。
Undo 表空間數據文件的初始大小取決於 innodb_page_size 值。對於默認的16KB頁面大小,初始撤消表空間文件大小爲10MiB。對於4KB,8KB,32KB和64KB頁面大小,初始Undo 表空間文件大小分別爲7MiB,8MiB,20MiB和40MiB。
關於Undo 表空間更多操作參見:https://dev.mysql.com/doc/refman/8.0/en/innodb-undo-tablespaces.html
3.4、臨時表空間
InnoDB 臨時表空間包括會話臨時表空間和全局臨時表空間
3.4.1、會話臨時表空間
當將InnoDB配置爲磁盤內部臨時表的存儲引擎時,會話臨時表空間將存儲用戶創建的臨時表和由優化程序創建的內部臨時表。從MySQL 8.0.16開始,用於磁盤內部臨時表的存儲引擎始終是InnoDB。 (以前,存儲引擎由internal_tmp_disk_storage_engine的值確定。)
在創建磁盤臨時表的第一個請求上,會話臨時表空間從臨時表空間池分配給會話。最多可將兩個表空間分配給一個會話,一個用於用戶創建的臨時表,另一個用於由優化程序創建的內部臨時表。分配給會話的臨時表空間用於該會話創建的所有磁盤上的臨時表。當會話斷開連接時,其臨時表空間將被刪除並釋放回池中。啓動服務器時,將創建10個臨時表空間的池。池的大小永遠不會縮小,並且表空間會根據需要自動添加到池中。在正常關閉或初始化中止時,將刪除臨時表空間池。會話臨時表空間文件在創建時大小爲5頁,並具有.ibt文件擴展名。
爲會話臨時表空間保留了40萬個空間ID。因爲每次啓動服務器時都會重新創建會話臨時表空間池,所以在關閉服務器時,會話臨時表空間的空間ID不會保留,並且可以重新使用。
innodb_temp_tablespaces_dir 變量定義了創建會話臨時表空間的位置。默認位置是數據目錄中的#innodb_temp目錄。如果無法創建臨時表空間池,則拒絕啓動。
shell> cd BASEDIR/data/#innodb_temp
shell> ls
temp_10.ibt temp_2.ibt temp_4.ibt temp_6.ibt temp_8.ibt
temp_1.ibt temp_3.ibt temp_5.ibt temp_7.ibt temp_9.ibt
在基於語句的複製(SBR)模式下,在從屬服務器上創建的臨時表駐留在單個會話臨時表空間中,該表空間僅在MySQL服務器關閉時才被中斷。
INNODB_SESSION_TEMP_TABLESPACES 表提供有關會話臨時表空間的元數據。
INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO 表提供有關在InnoDB實例中處於活動狀態的用戶創建的臨時表的元數據。
3.4.2、全局臨時表空間
全局臨時表空間(ibtmp1)存儲回滾段,以對用戶創建的臨時表進行更改。
innodb_temp_data_file_path 變量定義全局臨時表空間數據文件的相對路徑,名稱,大小和屬性。如果沒有爲innodb_temp_data_file_path指定值,則默認行爲是在 innodb_data_home_dir 目錄中創建一個名爲ibtmp1的自動擴展數據文件。初始文件大小略大於12MB。
全局臨時表空間在正常關閉或初始化中止時被刪除,並在每次啓動服務器時重新創建。全局臨時表空間在創建時會接收動態生成的空間ID。如果無法創建全局臨時表空間,則拒絕啓動。如果服務器意外停止,則不會刪除全局臨時表空間。在這種情況下,數據庫管理員可以手動刪除全局臨時表空間或重新啓動MySQL服務器。重新啓動MySQL服務器會自動刪除並重新創建全局臨時表空間。
全局臨時表空間不能駐留在原始設備上。
INFORMATION_SCHEMA.FILES提供有關全局臨時表空間的元數據。發出與此查詢類似的查詢以查看全局臨時表空間元數據:
mysql> SELECT * FROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME='innodb_temporary'\G
默認情況下,全局臨時表空間數據文件是自動擴展的,並根據需要增加大小。要確定全局臨時表空間數據文件是否正在自動擴展,請檢查 innodb_temp_data_file_path 設置:
mysql> SELECT @@innodb_temp_data_file_path;
+------------------------------+
| @@innodb_temp_data_file_path |
+------------------------------+
| ibtmp1:12M:autoextend |
+------------------------------+
要檢查全局臨時表空間數據文件的大小,請使用與此類似的查詢來查詢INFORMATION_SCHEMA.FILES表:
mysql> SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, INITIAL_SIZE, TOTAL_EXTENTS*EXTENT_SIZE
AS TotalSizeBytes, DATA_FREE, MAXIMUM_SIZE FROM INFORMATION_SCHEMA.FILES
WHERE TABLESPACE_NAME = 'innodb_temporary'\G
*************************** 1. row ***************************
FILE_NAME: ./ibtmp1
TABLESPACE_NAME: innodb_temporary
ENGINE: InnoDB
INITIAL_SIZE: 12582912
TotalSizeBytes: 12582912
DATA_FREE: 6291456
MAXIMUM_SIZE: NULL
TotalSizeBytes 顯示全局臨時表空間數據文件的當前大小。
檢查操作系統上的全局臨時表空間數據文件大小。全局臨時表空間數據文件位於 innodb_temp_data_file_path 變量定義的目錄中。
要回收全局臨時表空間數據文件佔用的磁盤空間,請重新啓動MySQL服務器。重新啓動服務器會根據 innodb_temp_data_file_path 定義的屬性刪除並重新創建全局臨時表空間數據文件。
要限制全局臨時表空間數據文件的大小,請配置innodb_temp_data_file_path以指定最大文件大小。例如:
[mysqld]
innodb_temp_data_file_path=ibtmp1:12M:autoextend:max:500M
配置 innodb_temp_data_file_path 要求重新啓動服務器。