InnoDB的表類型,邏輯存儲結構,物理存儲結構


表類型

對比Oracle支持的各種表類型,InnoDB存儲引擎表更像是Oracle中的索引組織表(index organized table)。在InnoDB存儲引擎表中,每張表都有個主鍵,如果在創建表時沒有顯式地定義主鍵(Primary Key),則InnoDB存儲引擎會按如下方式選擇或創建主鍵。

  1. 首先表中是否有非空的唯一索引(Unique NOT NULL),如果有,則該列即為主鍵。
  2. 不符合上述條件,InnoDB存儲引擎自動創建一個6個字節大小的指針。

邏輯存儲結構

InnoDB存儲引擎的邏輯存儲結構和Oracle大致相同,所有數據都被邏輯地存放在一個空間中,我們稱之為表空間(tablespace)。表空間又由(segment)、(extent)、(page)組成。頁在一些文檔中有時也稱為塊(block),1 extent = 64 pages,InnoDB存儲引擎的邏輯存儲結構大致如圖所示。

表空間

表空間可以看做是InnoDB存儲引擎邏輯結構的最高層,所有的數據都是存放在表空間中。默認情況下InnoDB存儲引擎有一個共享表空間ibdata1,即所有數據都放在這個表空間內。如果我們啟用了參數innodb_file_per_table,則每張表內的數據可以單獨放到一個表空間內。

對於啟用了innodb_file_per_table的參數選項,需要注意的是,每張表的表空間內存放的只是數據索引插入緩沖其他類的數據,如撤銷(Undo)信息系統事務信息二次寫緩沖(double write buffer)等還是存放在原來的共享表空間內。這也就說明了另一個問題:即使在啟用了參數innodb_file_per_table之后,共享表空間還是會不斷地增加其大小。

現在我們來做個實驗,實驗之前我已經將innodb_file_per_table設為ON了,看看初始共享表空間文件有多大:

show variables like 'innodb_file_per_table' \G

system ls -lh /usr/local/var/mysql/ibdata1

共享表空間ibdata1的大小為76M。

set autocommit=0;

update mytest set salary=0;

system ls -lh /usr/local/var/mysql/ibdata1

首先將自動提交設為0,即我們需要顯式提交事務(注意,上面結束時我們並沒有commit或者rollback該事務)。接着我們執行會產生大量Undo操作的語句update mytest set salary=0,完成后我們再觀察共享表空間,會發現ibdata1已經增長到了114MB,這就說明了共享表空間中還包含有Undo信息。如果我rollback這個事務,ibdata1這個表空間會不會縮減至原來的58MB大小?我們接下去就來驗證: 

rollback;

system ls -lh /usr/local/var/mysql/ibdata1

很“可惜”,還是114MB,即InnoDB存儲引擎不會在rollback時去收縮這個表空間。雖然InnoDB不會幫你回收這些空間,但是MySQL會自動判斷這些Undo信息是否需要,如果不需要,則會將這些空間標記為可用空間,供下次Undo使用。master thread每10秒會執行一次full purge操作。因此很有可能的一種情況是,你再次執行上述的UPDATE語句后,會發現ibdata1不會再增大了,那就是這個原因了。

上圖中顯示了表空間是由各個段組成的,常見的段有數據段索引段回滾段等。InnoDB存儲引擎表是索引組織的(index organized),因此數據即索引,索引即數據。那么數據段即為B+樹的頁節點(上圖的leaf node segment),索引段即為B+樹的非索引節點(上圖的non-leaf node segment)。

與Oracle不同的是,InnoDB存儲引擎對於段的管理是由引擎本身完成,這和Oracle的自動段空間管理(ASSM)類似,沒有手動段空間管理(MSSM)的方式,這從一定程度上簡化了DBA的管理。

需要注意的是,並不是每個對象都有段。因此更准確地說,表空間是由分散的頁組成。

區是由64個連續的頁組成的,每個頁大小為16KB,即每個區的大小為1MB。對於大的數據段,InnoDB存儲引擎最多每次可以申請4個區,以此來保證數據的順序性能。

在我們啟用了參數innodb_file_per_talbe后,創建的表默認大小是96KB。區是64個連續的頁,那創建的表的大小至少是1MB才對啊?其實這是因為在每個段開始時,先有32個頁大小的碎片頁(fragment page)來存放數據,當這些頁使用完之后才是64個連續頁的申請。

通過一個實驗來顯示InnoDB存儲引擎對於區的申請:

create table t1 (

  col1 int not null auto_increment,

  col2 varchar (7000),

  primary key(col1)

)engine=InnoDB;

system ls -lh /usr/local/var/mysql/test/t1.ibd

創建了t1表,col2字段設為varchar(7000),這樣能保證一個頁中可以存放2條記錄。可以看到,初始創建完t1后表空間默認大小為96KB.

同大多數數據庫一樣,InnoDB有頁(page)的概念(也可以稱為塊),頁是InnoDB磁盤管理的最小單位。與Oracle類似的是,Microsoft SQL Server數據庫默認每頁大小為8KB,不同於InnoDB頁的大小(16KB),且不可以更改(也許通過更改源碼可以)。

常見的頁類型有:

  1. 數據頁(B-tree Node)。
  2. Undo頁(Undo Log Page)。
  3. 系統頁(System Page)。
  4. 事務數據頁(Transaction system Page)。
  5. 插入緩沖位圖頁(Insert Buffer Bitmap)。
  6. 插入緩沖空閑列表頁(Insert Buffer Free List)。
  7. 未壓縮的二進制大對象頁(Uncompressed BLOB Page)。
  8. 壓縮的二進制大對象頁(Compressed BLOB Page)。

InnoDB存儲引擎是面向行的(row-oriented),也就是說數據的存放按行進行存放。每個頁存放的行記錄也是有硬性定義的,最多允許存放16KB/2~200行的記錄,即7992行記錄。這里提到面向行(row-oriented)的數據庫,那么也就是說,還存在有面向列(column-orientied)的數據庫。MySQL infobright儲存引擎就是按列來存放數據的,這對於數據倉庫下的分析類SQL語句的執行以及數據壓縮很有好處。類似的數據庫還有Sybase IQ、Google Big Table。面向列的數據庫是當前數據庫發展的一個方向。

物理存儲結構

從物理意義上來看,InnoDB表由共享表空間日志文件組(更准確地說,應該是Redo文件組)、表結構定義文件組成。若將innodb_file_per_table設置為on,則每個表將獨立地產生一個表空間文件,以ibd結尾,數據、索引、表的內部數據字典信息都將保存在這個單獨的表空間文件中表結構定義文件以frm結尾,這個是與存儲引擎無關的,任何存儲引擎的表結構定義文件都一樣,為.frm文件

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM