InnoDB儲存引擎——表

readyao發表於2017-03-18

表是關於特定實體的資料集合,也是關係型資料庫模型的核心。

1、索引組織表

InnoDB儲存引擎中,表都是根據主鍵順序組織存放的,這種儲存方式的表稱為索引組織表。在InnoDB儲存引擎表中,每個表都有個主鍵,如果在建立表的時候沒有顯示地定義主鍵,則InnoDB儲存引擎會按以下方式選擇或建立主鍵:
(1)首先判斷表中是否有非空的唯一索引,如果有,則該列即為主鍵。
(2)如果不符合上述條件,InnoDB儲存引擎自動建立一個6位元組大小的指標。
當表中有多個非空唯一索引時,InnoDB儲存引擎將選擇建表時第一個定義的非空唯一索引為主鍵。主鍵的選擇根據的是定義索引的順序,而不是建表時列的順序。

下面建立一個表,並沒有指定主鍵。因此會選擇非空的唯一索引。

mysql> create table test(
    -> a int not null,
    -> b int null,
    -> c int not null,
    -> d int not null,
    -> unique key(b),
    -> unique key(d),
    -> unique key(c));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test select 1,2,3,4;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into test select 5,6,7,8;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into test select 9,10,11,12;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

可以通過下面的語句判斷表的主鍵。

mysql> select a,b,c,d,_rowid from test;
+---+------+----+----+--------+
| a | b    | c  | d  | _rowid |
+---+------+----+----+--------+
| 1 |    2 |  3 |  4 |      4 |
| 5 |    6 |  7 |  8 |      8 |
| 9 |   10 | 11 | 12 |     12 |
+---+------+----+----+--------+
3 rows in set (0.00 sec)

_rowid可以顯示錶的主鍵,因此通過上述查詢可以找到表test的主鍵為d。
雖然b是第一個定義的唯一索引,但是b是NULL。所以d是第一個定義的非空唯一索引,InnoDB將其視為主鍵。_rowid只能用於檢視單個列為主鍵的情況,對於多列組成的主鍵就顯得無能為力了。

mysql> create table test2(
    -> a int,
    -> b int,
    -> primary key(a,b)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test2 select 1,1;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select a, _rowid from test2;
ERROR 1054 (42S22): Unknown column '_rowid' in 'field list'

2、InnoDB儲存引擎結構

從InnoDB儲存引擎的邏輯儲存結構看,所有資料都被邏輯地存放在一個空間中,稱之為表空間(tablespace)。表空間又由段(segment),區(extent),頁(page)組成。頁也被稱為塊(block)。下面是InnoDB儲存引擎的邏輯儲存結構。

這裡寫圖片描述

  • 表空間
    表空間可以看作是InnoDB儲存引擎邏輯結構的最高層,所有的資料都存放在表空間中。在預設情況下InnoDB儲存引擎有一個共享表空間ibdata1,即所有資料都存放在這個表空間中。如果使用者啟用了引數innodb_file_per_table,則每張表內的資料可以單獨放到一個表空間內。
mysql> show variables like 'innodb_file_per_table';    
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
1 row in set (0.00 sec)

如果使用者啟用了引數innodb_file_per_table,需要注意的是每張表的表空間記憶體放的只是資料、索引和插入緩衝Bitmap頁。
其它型別的資料,如回滾資訊,插入緩衝索引頁、系統事務資訊,二次寫緩衝等還是放在原來的共享表空間內。
這也說明,即使在啟用了引數innodb_file_per_table之後,共享表空間還是會不斷地增加其大小。


  • 從上圖中可以看出表空間是由各個段組成的,常見的段有資料段、索引段、回滾段等。InnoDB儲存引擎是索引組織的,因此資料即索引,索引即資料。那麼資料段即為B+樹的葉子節點(Leaf node segment),索引段即為B+樹的非索引節點(Non-leaf node segment)。

在InnoDB儲存引擎中,對段的管理都是由引擎本身完成的。


  • 區是由連續頁組成的空間,在任何情況下每個區的大小都為1MB。為了保證區中頁的連續性,InnoDB儲存引擎一次從磁碟申請4-5個區。在預設情況下,InnoDB儲存引擎頁的大小為16KB,即一個區中一共有64個連續的頁。

InnoDB 1.0.x版本開始引入壓縮頁,即每個頁的大小可以通過引數key_block_size設定為2K,4K,8K,因此每個區對應頁的數量就應該為512,256,128。
InnoDB 1.2.x版本新增了引數innodb_page_size,通過該引數可以將預設頁的大小設定為4K,8K,但是頁中的資料庫不是壓縮。這時區中頁的數量同樣也為256,128。總之,不論頁的大小怎麼變,區的大小總是1M。

在使用者啟動了引數innodb_file_per_table後,建立的表預設大小是96KB。


  • 頁(也被稱為塊)是InnoDB磁碟管理的最小單位。在InnoDB儲存引擎中,預設每個頁的大小為16KB。而從InnoDB 1.2.x版本開始,可以通過引數innodb_page_size將頁的大小設定為4K,8K,16K。若設定完成,則所有表中頁的大小都為innodb_page_size,不可以對其再次進行修改。除非通過mysqldump匯入和匯出操作來產生新的庫。
    在InnoDB儲存引擎中,常見的頁型別有:
    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-oriented的資料庫。
    MySql infobright儲存引擎就是按列來存放資料的,這對於資料倉儲下的分析類SQL語句的執行及資料壓縮非常有幫助。類似的資料庫還有Sybase IQ,Google Big Table。面向列的資料庫是當前資料庫發展的一個方向。

相關文章