MySQL之表

0. 概述

       本篇博客對其中結構性的內容並沒有進行深究,同時認爲深究的意義不是很大,如果各位有興趣,可以參閱《MySQL技術內幕》。

1. 索引組織表

       InnoDB存儲引擎中,表都是根據主鍵順序組織存放的,這種存儲方式的表稱爲索引組織表。

       如果在創建表時沒有顯示定義主鍵,則InnoDB 按照如下方式選擇或創建主鍵。

  1. 如果存在非空且唯一性索引,則將該列作爲主鍵。
  2. 如果不存在,則 MySQL 會自動創建一個 6 字節大小的指針作爲主鍵。

       

       

2. InnoDB 邏輯存儲結構

       InnoDB的邏輯結構中,所有數據都被邏輯地存放在一個空間中,稱爲表空間(tablespace)。表空間又由段(segment)、區(extent)、頁(page)組成。

在這裏插入圖片描述

2.1 表空間

       默認情況下,InnoDB有一個共享表空間ibdata1,所有數據都存放在這個表空間內。

2.2 段

       表空間由各個段組成,常見的段有數據段、索引段、回滾段等。

       由於InnoDB 表是索引組織的,因此數據即索引,索引即數據。數據段即爲 B+樹的葉子節點,索引段即爲B+ 樹的非葉子節點。

2.3 區

       區是由連續頁組成的空間,在任何情況下每個區的大小都爲 1 MB

       默認情況下,InnoDB 頁的大小爲 16 KB,即一個區中一共有 64 個連續的頁。

2.4 頁

       頁是InnoDB磁盤管理的最小單元,1.2 X版本後,可以將其設置爲4k8k16k

2.5 行

       InnoDB中數據是按行存放的,每頁最多存放 7992 行記錄。

3. InnoDB 行記錄格式

       InnoDB 提供了 CompactRedundant 兩種格式來存放行記錄數據。

       在 MySQL 5.1 版本中,默認設置爲 Compact 行格式。

3.1 Compact 行記錄格式

       Compact格式,其設計目標是高效地存儲數據。即一個頁中存放的行數據越多,其性能就越高。

在這裏插入圖片描述

       Compact 行記錄格式的首部是一個非 NULL 變長字段長度列表,並且其是按照列的順序逆序放置的。用1字節或者2字節表示。

       NULL 標誌位,該位指示了該行數據是否有 NULL 值,有則用 1 表示。用 1 字節表示。

3.2 Redundant 行記錄格式

       不同於 Compact 行記錄格式,Redundant 行記錄格式的首部是一個字段長度偏移列表,同樣是按照列的順序逆序放置的。

在這裏插入圖片描述

3.3 行溢出數據

       InnoDB可以將一條記錄中的某些數據存儲在真正的數據頁面之外,這部分數據稱爲行溢出數據。

3.4 Compressed 和 Dynamic 行記錄格式

       InnoDB 1.0.x 引入新的文件格式 Barracuda ,該文件格式擁有兩種新的行記錄格式:CompressedDynamic

       新的兩種記錄格式對於存放在 BLOB 中的數據採用了完全的行溢出的方式,如圖所示,在數據頁中只存放20個字節的指針,實際的數據都存放在 Off Page 中,而之前的 Compact 和Redundant 兩種格式會存放 768 個前綴字節

在這裏插入圖片描述

       Compressed 的另一個功能就是,存儲在其中的行數據會以 zlib 算法進行壓縮

3.5 CHAR 的行結構存儲

       從 MySQL 4.1 開始,CHAR(N) 中的 N 指的是字符的長度,而不是之前版本的字節長度。

       對於 UTF8CHAR(10) 類型的列,其最小可以存儲 10 字節的字符,而最大可以存儲30字節的字符。

       因此,對於多字節字符編碼的 CHAR 數據類型的存儲,InnoDB 存儲引擎在內部將其視爲變長字符類型,因此可以認爲多字節字符集的情況下,CHAR和VARCHAR的實際行存儲基本是沒有區別的,對於未能佔滿長度的字符還是填充 0x20

4. InnoDB 數據頁結構

在這裏插入圖片描述

4.1 File Header

       File Header用來記錄頁的一些頭信息。

在這裏插入圖片描述
       InnoDB存儲引擎中頁的類型:

在這裏插入圖片描述

4.2 Page Header

       Page Header用來記錄數據頁的狀態信息。

在這裏插入圖片描述

4.3 Infimum 和 Supremum Record

       在 InnoDB 中,每個數據頁中有兩個虛擬的行記錄,用來限定記錄的邊界。Infimum 記錄是比該頁中任何主鍵值都要小的值,Supremum 比任何可能大的值還要大的值。這兩個值在頁創建時被建立,並且在任何情況下都不會被刪除。

在這裏插入圖片描述

4.4 User Record 和 Free Space

       User Record 實際存儲行記錄的內容。

       Free Space 指的是空閒空間,是個鏈表數據結構。在一條記錄被刪除後,該空間會被加入到空閒列表中。

4.5 Page Direction

       Page Directory(頁目錄)中存放了記錄的相對位置。

       B+樹索引本身並不能查找到具體的的一條記錄,能找到的只是該記錄所在的頁。數據庫把頁載入到內存,然後通過 Page Directory 再進行二叉查找

4.6 File Trailer

       通過頁中的 File Trailer 部分,可以檢測頁是否已經完整地寫入磁盤(如寫入過程中磁盤損壞、機器關閉等)。

       在默認配置下,InnoDB 存儲引擎每次從磁盤讀取一個頁就會檢測該頁的完整性。

5. Named File Formats 機制

       Name File Formats機制用來解決不同版本下頁結構兼容性的機制。

6. 約束

6.1 數據完整性

       關係型數據庫系統和文件系統的一個不同點是,關係數據庫本身能保證存儲數據的完整性。

       約束的作用便是用來保證數據完整性

       數據完整性有以下三種形式:

  • 實體完整性保證表中有一個主鍵
  • 域完整性保證數據每列的值滿足特定的條件

       選擇合適的數據類型確保一個數據值滿足特定條件;

       外鍵(Foreign Key)約束;

       編寫觸發器;

       還可以考慮用 DEFAULT 約束作爲強制域完整性的一個方面。

  • 參照完整性保證兩證表之間的關係

       InnoDB 提供以下幾種約束:

  • Primary Key
  • Unique Key
  • Foreign Key
  • DEFAULT
  • NOT NULL

6.2 約束的創建和查找

       約束的創建可以採用以下兩種方式:

  1. 表建立時進行約束定義
  2. 利用 ALTER TABLE命令進行創建約束

6.3 約束和索引的區別

       約束更一個邏輯的概念,用來保證數據的完整性,而索引是一個數據結構,即有邏輯上的概念,在數據庫中還代表着物理存儲的方式

6.4 對錯誤數據的約束

       MySQL並沒有對非法數據的插入或更新進行約束,如果需要插入非法數據時,選擇報錯,必須設置參數sql_mode,來嚴格審覈輸入的參數。

6.5 ENUM 和 SET 約束

       MySQL不想SQLServer那樣,擁有CHECK約束,,只能提供離散的約束方式ENUMSET來解決一部分需求。

CREATE TABLE a(
	id INT,
    sex SET ('male','fenake');
);

       ENUMSET 的區別:

       SET 約束可以從裏面取多個值,而ENUM只能取1個。

6.6 觸發器與約束

       觸發器的作用是在執行INSERTDELETEUPDATE命令之前或之後自動調用SQL命令或存儲過程。

6.7 外鍵約束

       外鍵用來保證參照完整性。

       對父表的外鍵進行DELETEUPDATE操作時,子表有如下四種操作:

  • CASCADE
  • SET NULL
  • NO ACTION
  • RESTRICT

       CASCADE 表示當父表發生 DELETEUPDATE 操作時,對相應的子表中的數據也進行 DELETEUPDATE 操作。

       SET NULL 表示當父表發生 DELETE 或 UPDATE 操作時,相應的子表中的數據被更新爲 NULL 值,但是子表中相應的列必須允許設置爲 NULL 值。

       NO ACTION 表示當父表發生 DELETEUPDATE 操作時,拋出錯誤,不允許這類操作發生。

       RESTRICT 表示當父表發生 DELETEUPDATE 操作時,拋出錯誤,不允許這類操作發生。

       RESTRICT是在修改或者刪除之前去檢查從表中是否有對應的數據,如果有,拒絕操作,而NO ACTION是在修改或者刪除完以後去檢查從表中是否有對應的數據,如果有,拒絕操作,但是在MySQL中,外鍵約束都會立即檢查,所以兩者等價。

       RESTRICT 是默認的外鍵設置

7. 視圖

       視圖是一個命名的虛表,與持久表不同的是,視圖中的數據沒有實際的物理存儲。

7.1 視圖的作用

       在一定程度上起到一個安全層的作用:程序本身不需要關心基表(base table)的結構,只需要按照視圖定義來讀取數據或更新數據。

8. 分區表

8.1 分區概述

       分區指將一個表或索引分解爲多個更小、更可管理的部分。

       就訪問數據庫的應用而言,從邏輯上講,只有一個表或一個索引,但是在物理上這個表或索引可能由數十個物理分區組成。

       MySQL 數據庫支持的分區類型爲水平分區(指將同一表中不同行的記錄分配到不同的物理文件中),並不支持垂直分區(指將同一表中不同列的記錄分配到不同的物理文件中)。

       分區可能會給某些 SQL 語句性能帶來提高,但是分區主要用於數據庫高可用性的管理。在OLTP應用中,對於分區的使用應該非常小心。

8.2 分區類型

8.2.1 RANGE 分區

       行數據基於一個給定連續區間的列值被放入分區。

       啓用分區之後,表不再由一個 ibd 文件組成了,而是由建立分區時的各個分區 ibd 文件組成

       創建一個 id 列的區間分區表。當 id 小於 10 時,數據插入 p0 分區。當 id 大於等於 10 小於 20 時,數據插入 p1 分區。

create table t(
	id INT
)ENGINE = INNODB
PARTITION BY RANGE (id(
PARTITION P0 VALUES LESS THAN(10),
PARTITION P1 VALUES LESS THAN(10));
)

       當插入一個不再分區中定義的值時,MySQL 會拋出一個異常。

       RANGE 分區主要用於日期列的分區,例如對於銷售類的表,可以根據年來分區存放銷售記錄。

8.2.2 LIST 分區

       和RANGE分區類型,只是LIST分區面向的是離散的值,而非連續的。

CREATE TABLE t(
	a INT,
    b INT
)ENGINE = INNODB
PARTITION BY RANGE (b)(
PARTITION p0 VALUES IN (1,3,5,7,9),
PARTITION p1 VALUES IN (0,2,4,6,8));

       在用 INSERT 插入多個行數據的過程中遇到分區未定義的值時,MyISAMInnoDB 的處理完全不同。MyISAM 會將之前的行數據都插入,但之後的數據不會被插入。而InnoDB 將其視爲一個事務,因此沒有任何數據插入。

8.2.3 HASH 分區

       根據用戶自定義的表達式的返回值來進行分區,返回值不能爲負數。

       HASH 分區的目的是將數據均勻地分佈到預先定義地各個分區中,保證各分區地數據數量大致是一樣的。

       要使用 HASH分區來分割一個表,要在 CHEATE TABLE語句添加一個 PARTITION BY HASH(expr)子句,其中 “expr” 是返回一個整數的表達式。

CREATE table t_hash(
	a INT,
    b DATETIME
)ENGINE = InnoDB
PARTITION BY HASH (YEAR(b))
PARTITIONS 4;

8.2.4 KEY 分區

       根據MySQL數據庫提供的哈希函數進行分區。

       KEY 分區和 HASH 分區相似,不同在於 HASH 分區使用用戶定義的函數進行分區,KEY 分區使用 MySQL 數據庫提供的函數進行分區。

8.2.5 COLUMN 分區

       對於前四種分區,分區的條件是:整型(integer),如果不是整型,那應該需要通過函數將其轉換爲整性。

       COLUMNS 分區可以直接使用非整型的數據進行分區,分區根據類型直接比較而得,不需要轉換爲整性。

8.3 子分區

       子分區是在分區得基礎上再進行分區,MySQL是在分區的基礎上再進行分區,有時也稱這種分區爲符合分區。MySQL數據庫允許再RANGELIST的分區上再進行HASHKEY的子分區。

CREATE TABLE ts(
	a INT,
    b DATE
)
PARTITION BY RANGE ( YEAR(b))
SUBPARTITIONS 2(
PARTITION p0 VALUES LESS THAN (1990),		
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE  
);

       表 ts 先根據 b 列進行了 RANGE 分區,然後又進行了一次 HASH 分區,所以分區的數量應該爲(3*2=6)個

8.4 分區中的 NULL 值

       MySQL 允許對NULL值做分區。

       MySQL 數據庫得分區總是視 NULL 值小於任何得一個非 NULL值。

       對於 RANGE 分區,如果向分區列插入了 NULL 值,則 MySQL 數據庫會將該值放入最左邊的分區。

       在 LIST 分區下要使用 NULL 值,則必須顯示地指出那個分區中放入 NULL 值,否則會報錯。

       HASHKEY 分區對於 NULL 的處理方式和 RANGE 分區、LIST 分區不一樣。任何分區函數都會將含有 NULL 值得記錄返回爲 0

8.5 分區和性能

       對於OLAP(在線分析處理)的應用,分區的確是可以很好地提高查詢地性能,因爲OLAP應用大多數查詢需要頻繁地掃描一張很大的表。

       對於OLTP(在線事務處理)的應用,則未必,如果涉及不好的分區會帶來嚴重的性能問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章