1. 索引組織表
? 在InnoDB存儲引擎中,表都是根據(jù)主鍵順序組織存放的,這種存儲方式的表稱為索引組織表.
? 在InnoDB存儲引擎中,每張表都有個主鍵,如果在創(chuàng)建表的時候沒有顯式的定義出主鍵會按照下面的方式選擇或者創(chuàng)建一個主鍵字段:
- 如果有非空的唯一索引,選擇這個字段作為主鍵字段(如果有多個,按照定義索引的順序選擇第一個字段)
- 如果不符合第一條,自動創(chuàng)建一個6字節(jié)大小的指針.
2. InnoDB邏輯存儲結(jié)構(gòu)
? 從InnoDB存儲引擎的邏輯存儲結(jié)構(gòu)看,所有數(shù)據(jù)都被邏輯地存放在一個空間中,稱之為表空間.表空間又由段(segment),區(qū)(extent),頁(page,默認(rèn)為16K)組成.
(1). 表空間
? 表空間可以看做是InnoDB存儲引擎邏輯結(jié)構(gòu)的最高層,所有的數(shù)據(jù)都存放在表空間中.如果用戶啟用了參數(shù)innodb_file_per_table,則每張表都可以有一個獨(dú)立的表空間.
? 但要注意的是,每張表的獨(dú)立表空間只存放數(shù)據(jù),索引和插入緩沖Bitmap頁,其他類的數(shù)據(jù)(undo回滾信息,插入緩沖索引頁,系統(tǒng)事務(wù)信息,二次寫緩沖等等)還是存放在共享表空間的.那么意味著,就算開啟了innodb_file_per_table參數(shù),共享表空間還是會不斷的增大.
? 在共享表空間中的空間如果失效(如被覆蓋掉的undo信息),并不會立即回收這些內(nèi)存,而是標(biāo)記為可用空間,供下次使用.
(2). 段
? 表空間是又一個一個段組成的,常見的段有數(shù)據(jù)段,索引段,回滾段等等.
? InnoDB存儲引擎是索引組織的,因此數(shù)據(jù)即索引,索引即數(shù)據(jù).那么數(shù)據(jù)段即為B+樹的葉子節(jié)點(diǎn),索引段即為B+數(shù)的非葉子節(jié)點(diǎn).回滾段較為特殊,暫不介紹.
? 才InnoDB存儲引擎中,對段的管理都是由引擎自身所完成.
(3). 區(qū)
? 區(qū)是由連續(xù)頁組成的空間,在任何情況下每個區(qū)的大小都為1MB,為了保證區(qū)中頁的完整性,InnoDB存儲引擎一次性會從磁盤申請4~5個區(qū).在默認(rèn)情況下,InnoDB存儲引擎頁的大小為16KB,即一個區(qū)中有64個連續(xù)的頁.
? 但是這64個連續(xù)的頁并不是在申請完區(qū)空間后就得到的.InnoDB存儲引擎在每一個區(qū)開始使用時會使用32個頁大小的碎片頁來存放數(shù)據(jù),這些頁使用完時候才會一次性申請64個連續(xù)頁.這樣的目的是對于一些小表,或者undo這類的段,可以在開始時申請較少的空間,節(jié)省磁盤容量的開銷.
(4). 頁
? 頁是InnoDB磁盤管理的最小單位,默認(rèn)每個頁的大小為16KB.從InnoDB 1.2.x版本開始,可以通過innodb_page_size將頁的大小設(shè)置為4K,8K,16K.
常見的頁類型有:
- 數(shù)據(jù)頁(B-tree Node)
- undo頁(undo Log Page)
- 系統(tǒng)頁(System Page)
- 事務(wù)數(shù)據(jù)頁(Transaction system Page)
- 插入緩沖位圖頁(Insert Buffer Bitmap)
- 插入緩沖空閑列表頁(Insert Buffer Free List)
- 未壓縮的二進(jìn)制大對象頁(Uncompressed BLOB Page)
- 壓縮的二進(jìn)制大對象頁(compressed BLOB Page)
(5). 行
? InnoDB存儲引擎是面向列的 ,也就是說數(shù)據(jù)是按行進(jìn)行存放的.每個頁存放的行記錄也是有硬性定義的,最多允許存放7992行數(shù)據(jù)(16KB/2-200).
3. InnoDB行記錄格式
? InnoDB存儲引擎和大多數(shù)數(shù)據(jù)庫一樣,記錄是以行的形式存儲的.在InnoDB 1.0.x版本之前,InnoDB存儲引擎提供了Compact和Redundant兩中格式來存放行記錄數(shù)據(jù).在MySQL 5.1版本中,默認(rèn)設(shè)置為Compact版本.
(1). Compact行記錄格式
? Compact行記錄實(shí)在MySQL 5.0中引入的,其設(shè)計目的是高效的存儲數(shù)據(jù).一個頁中存放的行數(shù)據(jù)越多,其性能就越高.
? Compact行記錄格式由變長字段長度列表,NULL標(biāo)志位,記錄頭信息,列數(shù)據(jù)1,列數(shù)據(jù)2.....組成.
? 其中變長字段長度列表是按照列的逆序排列的,有若干個1或者2字節(jié)的二進(jìn)制數(shù)組成(1字節(jié)代表225的長度,2字節(jié)則為65535).變長字段長度列表之后的第二個部分是NULL標(biāo)志為,改為只是了該行數(shù)據(jù)是否有NULL值,以二進(jìn)制的形式展示.接下來是記錄頭信息,固定站5字節(jié),含義見下表:
名稱 | 大小 | 描述 |
---|---|---|
() | 1 | 未知 |
() | 1 | 未知 |
delete_flag | 1 | 該行是否被刪除 |
min_rec_flag | 1 | 為1則代表該記錄是預(yù)先被定義為最小的記錄 |
n_owned | 4 | 該記錄擁有的記錄數(shù) |
heap_no | 13 | 索引堆中該條記錄的排序記錄 |
record_type | 3 | 記錄類型:000表示普通,001表示B+數(shù)節(jié)點(diǎn)指針,010表示Infimum,011表示Supermum,1xx表示保留 |
next_record | 16 | 頁中下一條記錄的相對位置 |
Total | 40 |
? 最后的部分就是存儲每個列的數(shù)據(jù),NULL不占該部分的任何空間.
? 每行數(shù)據(jù)除了用戶定義的列外,還有兩個隱藏列,事務(wù)ID列(6字節(jié))和回滾指針列(7字節(jié)).如果InnoDB表沒有定義主鍵,每行還會增加一個rowid列.
(2). Redundant行記錄格式
? Redundant是MySQL 5.0之前InnoDB的行記錄存儲方式,不同于Compact方式,首部是一個字段長度偏移列表,同樣是逆序,然后是記錄頭信息,緊跟著列數(shù)據(jù)1,列數(shù)據(jù)2......
名稱 | 大小 | 描述 |
---|---|---|
() | 1 | 未知 |
() | 1 | 未知 |
delete_flag | 1 | 該行是否已經(jīng)被刪除 |
min_rec_flag | 1 | 如果為1,則該記錄是預(yù)先被定義為最小的記錄 |
n_owned | 4 | 該記錄擁有的記錄數(shù) |
heap_no | 13 | 索引堆中該條記錄的索引號 |
n_fields | 10 | 記錄中列的數(shù)量 |
1byte_offs_flag | 1 | 偏移列表為1字節(jié)還是2字節(jié) |
next_record | 16 | 頁中下一條記錄的相對位置 |
Total | 48 |
(3). 行溢出數(shù)據(jù)
? InnoDB存儲引擎可以將一條記錄中的某些數(shù)據(jù)存儲在真正的數(shù)據(jù)頁之外,一般為BLOB,LOB這種大對象列類型會這樣存儲.但是需要注意的是,BLOB也可以不將數(shù)據(jù)放在溢出頁面,VARCHAR也可能會存在溢出頁面之中.
? VARCHAR類型最大支持65535字節(jié),所以對于不同的編碼格式,存儲的數(shù)據(jù)長度是不一致的.此外這個長度是對于一行中的所有列VARCHAR總長度和,如果這個總長度超出了65535字節(jié),就發(fā)生了溢出,會將數(shù)據(jù)存放在Uncompress BLOB頁中.
? InnoDB存儲引擎表是索引組織的,即B+Tree的結(jié)構(gòu),這樣每個頁中至少要存放兩條數(shù)據(jù)才有意義,如果一行的大小不允許同一頁中在存放下一行數(shù)據(jù),那么這一行數(shù)據(jù)就會被存放入溢出頁中.
? 對于TEXT和BLOB類型的數(shù)據(jù),與VARCHAR一樣.
? 大多數(shù)情況下,BLOB類型的數(shù)據(jù)都很大,都會溢出的,數(shù)據(jù)數(shù)據(jù)都是保存在BLOB頁中的,數(shù)據(jù)頁只保存前768字節(jié).
(4). Compressed和Dynamic行記錄格式
? InnoDB 1.0.x版本開始引入了新的文件格式,成為Barracuda文件格式,有兩種行記錄格式:Compressed和Dynamic.這兩種新的記錄格式對于存放BLOB中的數(shù)據(jù)采用了完全的行溢出方式.
? 除此之外,Compressed行記錄格式的另一個功能是存儲在其中的行數(shù)據(jù)會以zlib的算法進(jìn)行壓縮.
(5). CHAR的行結(jié)構(gòu)存儲
? 從MySQL 4.1版本開始,CHR(N)中的N指的是字符的長度,而不是存儲數(shù)據(jù)所占字節(jié)長度.也就是說不同的字符集下,CHAR類型存儲的不是定長數(shù)據(jù).
4. InnoDB數(shù)據(jù)頁結(jié)構(gòu)
? 頁是InnoDB存儲引擎管理數(shù)據(jù)庫的磁盤最小單位,InnoDB數(shù)據(jù)頁由一下7部分組成:
- File Header(文件頭)
- Page Header(頁頭)
- Infimun和Supermum Records
- User Records(行記錄)
- Free Space(空閑空間)
- Page Directory(頁目錄)
- File Trailer(文件結(jié)尾信息)
(1). File Header
? File Header用來記錄頁的一些頭信息,由以下8部分組成共38字節(jié).
File Header組成部分:
名稱 | 大小(字節(jié)) | 說明 |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM | 4 | MySQL 4.0.14之前該值為0,之后代表該頁的checksum值 |
FIL_PAGE_OFFSET | 4 | 表空間中頁的偏移值. |
FIL_PAGE_PREV | 4 | 當(dāng)前頁的上一頁(B+數(shù)決定葉子節(jié)點(diǎn)必定是雙向鏈表) |
FIL_PAGE_NEXT | 4 | 當(dāng)前頁的下一頁 |
FIL_PAGE_LSN | 8 | 代表該頁最后被修改的日志位置LSN(Log Sequence number) |
FIL_PAGE_TYPE | 2 | InnoDB存儲引擎頁的類型(0x45BF代表數(shù)據(jù)頁) |
FIL_PAGE_FILE_FLUSH_LSN | 8 | 在系統(tǒng)表空間的頁中定義,代表文件至少被更新到了該LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | 從MySQL 4.1開始代表該頁屬于那個表空間 |
InnoDB存儲引擎中頁的類型:
名稱 | 十六進(jìn)制表示 | 解釋 |
---|---|---|
FIL_PAGE_INDEX | 0x45BF | B+數(shù)葉節(jié)點(diǎn) |
FIL_PAGE_UNDO_LOG | 0x0002 | Undo log頁 |
FIL_PAGE_INODE | 0x0003 | 索引節(jié)點(diǎn) |
FIL_PAGE_IBUF_FREE_LIST | 0x0004 | Insert Buffer空閑列表 |
FIL_PAGE_TYPE_ALLOCATED | 0x0000 | 該頁為最新分配 |
FIL_PAGE_IBUF_BITMAP | 0x0005 | Insert Buffer位圖 |
FIL_PAGE_TYPE_SYS | 0x0006 | 系統(tǒng)頁 |
FIL_PAGE_TYPE_TRX_SYS | 0x0007 | 事物系統(tǒng)數(shù)據(jù) |
FIL_PAGE_TYPE_FSP_HDR | 0x0008 | File Space Header |
FIL_PAGE_TYPE_XDES | 0x0009 | 拓展描述頁 |
FIL_PAGE_TYPE_BLOB | 0x000A | BLOB頁 |
(2). Page Header
? 該部分用來記錄數(shù)據(jù)頁的狀態(tài)信息.由14部分組成,共56字節(jié).
名稱 | 大小(字節(jié)) | 說明 |
---|---|---|
PAGE_N_DIR_SLOTS | 2 | 在Page Directory(頁目錄)中的Slot(槽)數(shù) |
PAGE_HEAP_TOP | 2 | 堆中第一個記錄的指針,記錄在頁中的數(shù)據(jù)以堆的形式存放 |
PAGE_N_HEAP | 2 | 堆中的記錄數(shù) |
PAGE_FREE | 2 | 指向可重用空間的首指針 |
PAGE_GARBAGE | 2 | 已刪除記錄的字節(jié)數(shù) |
PAGE_LAST_INSERT | 2 | 最后插入記錄的位置 |
PAGE_DIRECTION | 2 | 最后插入的方向(0x01,ox02,0x03,0x04,0x05) |
PAGE_N_DIRECTION | 2 | 一個方向上連續(xù)插入記錄的數(shù)量 |
PAGE_N_RECS | 2 | 該頁中記錄的數(shù)量 |
PAGE_MAX_TRX_ID | 8 | 就當(dāng)前頁的最大事務(wù)ID |
PAGE_LEVEL | 2 | 當(dāng)前頁在索引數(shù)中的位置,0x00代表葉節(jié)點(diǎn) |
PAGE_INDEX_ID | 8 | 索引ID |
PAGE_BTR_SEG_LEAF | 10 | B+樹數(shù)據(jù)頁非葉節(jié)點(diǎn)所在段的segment header.(僅在B+數(shù)的root頁中被定義) |
PAGE_BTR_SEG_TOP | 10 | B+樹數(shù)據(jù)頁所在段的segment header.(僅在B+數(shù)的root頁中被定義) |
(3). Infimum和Supremum Record
? 每個數(shù)據(jù)頁中有兩個虛擬的行記錄,用來限定記錄的邊界.Infimum用來記錄比頁中任何主鍵值都要小的值,Supermum指比任何可能大的值還要大的值.這兩個值在頁創(chuàng)立時建立,任何情況下不會被刪除.
(4). User Record和Free Space
? User Record指數(shù)據(jù)存儲行記錄的內(nèi)容.
? Free Space值空閑空間,也是個鏈表數(shù)據(jù)結(jié)構(gòu).一條記錄被刪除后會被加入到空閑鏈表中.
(5). Page Directory
? 頁目錄,其中存放了記錄的==相對==位置,有時候這些記錄指針被稱為Slots(槽).在InnoDB中并不是每個記錄擁有一個槽,InnoDB存儲引擎的槽是一個稀疏目錄,一個槽中可能包含多個記錄.
(6). File Trailer
? 為了檢測頁是否已經(jīng)完整的寫入磁盤,設(shè)置了File Trailer部分.
? 該部分只有一個FIL_PAGE_END_LSN部分,占用8字節(jié).前4字節(jié)代表該頁的checksum值,最后4字節(jié)和File Header中的FIL_PAGE_LSN相同.這兩個值用于與File Header中的FIL_PAGE_SPACE_OR_CHKSUM和FIL_PAGE_LSN進(jìn)行比較,依次來確保頁的完整性.
? 默認(rèn)情況下,每次從磁盤讀取一個頁就會檢查依次該頁的完整性,就是通過檢查File Trailer部分進(jìn)行檢測.
5. Named File Formats機(jī)制
? 目的是解決不同版本下頁結(jié)構(gòu)兼容性問題.
? InnoDB存儲引擎不同版本之間新的文件格式總是包含于之前版本的頁格式.
6. 約束
(1). 數(shù)據(jù)完整性
? 關(guān)系型數(shù)據(jù)庫和文件系統(tǒng)的一個不同點(diǎn)就是關(guān)系數(shù)據(jù)庫本身能保證數(shù)據(jù)的完整性,不需要應(yīng)用程序的空值,而文件系統(tǒng)一般需要在程序端進(jìn)行控制.
數(shù)據(jù)完整性有一下三種形式:
- 實(shí)體完整性保證表中有一個主鍵
- 域完整性保證每列數(shù)據(jù)的值滿足特定的條件,實(shí)現(xiàn):
- 選擇合適的數(shù)據(jù)類型
- 外鍵約束
- 觸發(fā)器
- default約束(默認(rèn)值)
- 參照完整性保證兩張表之間的關(guān)系(外鍵,觸發(fā)器)
(2). 約束的創(chuàng)建和查找
約束的創(chuàng)建可以使用一下兩種方式:
- 建立表時進(jìn)行約束的定義
- 利用alter table命令創(chuàng)建約束
對于Unique Key(唯一索引)還能通過create unique index命令創(chuàng)建.
create table 庫名.表名(
字段名1 類型[(寬度) 約束條件],
字段名2 類型[(寬度) 約束條件],
字段名3 類型[(寬度) 約束條件]
);
// 常見約束
primary key (PK) #標(biāo)識該字段為該表的主鍵,可以唯一的標(biāo)識記錄,主鍵就是不為空且唯一當(dāng)然其還有加速查詢的作用
foreign key (FK) #標(biāo)識該字段為該表的外鍵魏颓,用來建立表與表的關(guān)聯(lián)關(guān)系
not null #標(biāo)識該字段不能為空
unique key (UK) #標(biāo)識該字段的值是唯一的
auto_increment #標(biāo)識該字段的值自動增長(整數(shù)類型,而且為主鍵)
default #為該字段設(shè)置默認(rèn)值
unsigned #將整型設(shè)置為無符號即正數(shù)
zerofill #不夠使用0進(jìn)行填充
(3). 約束和索引的區(qū)別
? 當(dāng)用戶創(chuàng)建了一個唯一索引就創(chuàng)建了一個唯一的約束.
? 約束是一個邏輯的概念,用來保護(hù)數(shù)據(jù)的完整性,而索引是一個數(shù)據(jù)結(jié)構(gòu),既有邏輯上的概念,在數(shù)據(jù)庫中還代表著物理存儲的方式.
(4). 對錯誤數(shù)據(jù)的約束
? MySQL數(shù)據(jù)庫允許非法的或者不正確的數(shù)據(jù)插入或更新,又或者可以在數(shù)據(jù)庫內(nèi)部將其轉(zhuǎn)化為一個合法的值,數(shù)據(jù)庫本身沒有對數(shù)據(jù)的正確性進(jìn)行約束.
(5). ENUM和SET約束
? MySQL數(shù)據(jù)庫不支持傳統(tǒng)的CHECK約束,但是通過ENUM(枚舉類型,單選)和SET(集合類型,多選,求和)類型可以解決部分這樣的約束要求.但對于連續(xù)值的萬為約束或更復(fù)雜的約束,需要使用觸發(fā)器來實(shí)現(xiàn).
(6). 觸發(fā)器與約束
? 觸發(fā)器的作用是在執(zhí)行insert,delete或者update命令之前或者之后自動調(diào)用SQL命令或存儲過程.
? 創(chuàng)建觸發(fā)器的命令如下,只有Super權(quán)限的MySQL用戶才可以執(zhí)行這條命令:
create trigger 觸發(fā)器名 before|after 觸發(fā)事件
on 表名 for each row
begin
執(zhí)行語句
end;
? 最多可以為一張表建立6個觸發(fā)器,即inser,delete和update三種操作各一個before和after觸發(fā)器.
? MySQL只支持for each row的觸發(fā)器,即按每行記錄進(jìn)行出發(fā).
(7). 外鍵約束
? 外鍵用來保證參照完整性,InnoDB存儲引擎完整支持外鍵約束.
? 一般來說,被引用的表被稱為父表,引用表稱為子表.外鍵定義時的on delete和on update表示在對父表進(jìn)行delete和update操作時,對子表所進(jìn)行的操作.
foreign key
子表名(子表字段) references 父表名(父表字段)
[on delete restrict|cascade|set null|no action]
[on update restrict|cascade|set null|no action]
- cascade:對子表進(jìn)行同步
- set null:設(shè)置子表為null(子表中的字段不能NOT NULL)
- no action:不允許父表的此操作,拋出異常
- restrict:同上
? MySQL中最后的兩條是一樣的.
? InnoDB存儲引擎會在外鍵建立的同時自動為外鍵列加上一個索引,可以很好的避免死鎖問題.
7. 視圖
? MySQL數(shù)據(jù)庫中,視圖是一個命名的虛表,由一個SQL查詢來定義,可以當(dāng)做表使用,但沒有物理存儲.
(1). 視圖的作用
create view 視圖名 [視圖列名]
as 查詢語句
[with [cascaded|local] check option]
? 視圖的主要用途之一就是被用作一個抽象裝置,程序本身不需要關(guān)心基表的結(jié)構(gòu),只需要按照視圖定義來取數(shù)據(jù)或者更新數(shù)據(jù).同時起到一個安全層的作用.
? 用戶對某些視圖的更新操作,其本質(zhì)就是通過的視圖的定義來更新基本表.視圖定義中的with check option就是針對于可更新視圖的更新檢查.加上該選項,MySQL數(shù)據(jù)庫會對更新視圖插入的數(shù)據(jù)進(jìn)行檢查,對于不滿足==視圖定義條件(也就是查詢語句中的條件查詢)==的插入,會拋出一個異常.不允許數(shù)據(jù)更新.
(2). 物化視圖
? 物化視圖是指該視圖不是基于表的虛表,而是根據(jù)基表實(shí)際存在的實(shí)體表.可用于預(yù)先計算并保存多表的鏈接,聚集等耗時的SQL操作結(jié)果.
物化視圖的刷新模式:
- on demand:需要時刷新
- on commit:實(shí)時刷新
刷新的方法:
- fast:局部刷新
- complete:全局刷新
- force:通過判斷選擇前兩種
- never:不進(jìn)行刷新
? MySQL數(shù)據(jù)庫不支持物化視圖,不過可以使用其他方式實(shí)現(xiàn).on demand的物化視圖可以通過定時吧數(shù)據(jù)轉(zhuǎn)入另一張表來完成,其中不需要定義語法上的視圖.如果要實(shí)現(xiàn)on commit的物化視圖,需要使用觸發(fā)器.
8. 分區(qū)表
(1). 概述
? 分區(qū)功能并不是在存儲引擎層完成的,常見的存儲引擎都支持,但不是所有.
? 分區(qū)的過程是將一個表或者索引分解為多個更小,更可管理的部分.將訪問數(shù)據(jù)庫的應(yīng)用而言,從邏輯上講,只有一個表或者索引.但是在物理上這個表或者索引可能由數(shù)十個物理分區(qū)組成.每一個分區(qū)都是獨(dú)立的對象,可以獨(dú)自處理,也可所為一個更大的對象的一部分進(jìn)行處理.
? MySQL支持的分區(qū)類型為水平分區(qū)(將不同行的數(shù)據(jù)分到不同的物理文件中),而不支持垂直分區(qū)(同之前,不同列).此外,MySQL分區(qū)是局部分區(qū)索引(一個分區(qū)中既存放了數(shù)據(jù),有存放了索引),另一種是全局分區(qū)(數(shù)據(jù)存放在各個分區(qū)中,所有數(shù)據(jù)的索引放在一個對象中).
? 分區(qū)主要用于數(shù)據(jù)庫高可用性的管理.
當(dāng)前MySQL數(shù)據(jù)庫支持一下幾種類型的分區(qū):
- RANGE分區(qū):行數(shù)據(jù)在一個連續(xù)的給定區(qū)間的數(shù)據(jù)放入一個分區(qū).
- LIST分區(qū):面向離散的值
- HASH分區(qū):根據(jù)自定義的表達(dá)式的返回值進(jìn)行分區(qū)
- KEY分區(qū):根據(jù)MySQL數(shù)據(jù)庫提供的哈希函數(shù)來進(jìn)行分區(qū)
? 不論建立何種類型的分區(qū),如果表中存在主鍵或者唯一索引,那么分區(qū)別必須是唯一索引的一個組成部分.
? 唯一索引可以是允許NULL值的,并且分區(qū)列只要是唯一索引的一個部分就可以了(多個唯一索引之一).
(2). 分區(qū)類型
1). RANGE分區(qū)
? RANGE分區(qū),是最常用的一種分區(qū)類型.
create table t(
value int
)engine=InnoDB
partition by RANGE(value)(
partition p0 values less than (10),
partition p1 values less than (20),
partition p3 values less than maxvalue
);
? 這里范圍是[10,20)插入p1,右邊為開區(qū)間.
? 當(dāng)插入一個不在分區(qū)中定義的值是,MySQL數(shù)據(jù)庫會拋出異常,我們可以通過添加一個maxvalue值作為無限大來解決這個問題.
? RANGE主要用于日期列的分區(qū).如下所示:
create table t_date(
value datetime
)engine=InnoDB
partition by RANGE(year(value))(
partition p2008 values less than (2009),
partition p2009 values less than (2010),
partition pfuture values less than maxvalue
);
? 要刪除響應(yīng)時間的記錄只需要刪除分區(qū)即可(刪除分區(qū)約束):
alter table 表名 drop partition 分區(qū)名;
? 其次,在進(jìn)行查詢語句時,SQL優(yōu)化器會對查詢范圍進(jìn)行裁剪,只搜索部分分區(qū),所以可以大幅度優(yōu)化查詢速度.這被稱為Partition Pruning(分區(qū)修減).對于RANGE分區(qū)的查詢,優(yōu)化器只能對YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()這類函數(shù)進(jìn)行優(yōu)化選擇.
注意:
where value>='2008-1-1' and value<='2008-12-31';
和
where value>='2008-1-1' and value<'2009-1-1';
的優(yōu)化是不同的,后者會搜索兩個分區(qū)p2008和p2009
所以應(yīng)當(dāng)根據(jù)分區(qū)對SQL進(jìn)行優(yōu)化.
2). LIST分區(qū)
? 分區(qū)列的值是離散的.
create table t(
value int
)engine=InnoDB
partition by RANGE(value)(
partition p0 values in (1,3,5,7,9),
partition p1 values in (0,2,4,6,8)
);
? 如果插入值不在分區(qū)的定義中,MySQL數(shù)據(jù)庫同樣會拋出異常.
? 在用insert插入多個行數(shù)據(jù)的過程中遇到分區(qū)未定義的值時,InnoDB存儲引擎會撤銷所有插入的操作,其他存儲引擎有不同的操作.
3). HASH分區(qū)
? HASH分區(qū)的目的是將數(shù)據(jù)均勻的分布到預(yù)先定義的各個分區(qū)中,保證個分區(qū)的數(shù)據(jù)數(shù)量大致是一樣的.在RANGE和LIST分區(qū)中,必須明確制定一個給定的列支或者列值集合應(yīng)該保存在那個分區(qū)中,但在HASH分區(qū)中,MySQL自動的完成這些操作.
? 需要使用partitions制定分區(qū)的數(shù)量.否則默認(rèn)為1.
create table t(
value int
)engine=InnoDB
partition by HASH(value)
partitions 4;
還支持一種LINEAR HASH的分區(qū)(線性HASH).哈希函數(shù)的步驟如下:
- 給分區(qū)數(shù)量向上取整為2的冪值,記為v
- N = F( num ) & ( v-1 )
- 如果N>=分區(qū)數(shù)量,則在進(jìn)行如下操作:
- v = CEIL( v/2 ) 除2,取整
- N = N & ( v-1 ) 二次進(jìn)行哈希
? LINEAR HASH分區(qū)的優(yōu)點(diǎn)在于,增加,刪除,合并和拆分分區(qū)將變得更加快捷.缺點(diǎn)在于各個分區(qū)間的數(shù)據(jù)分布可能不如HASH分區(qū)均衡.
4). KEY分區(qū)
? KEY分區(qū)使用MySQL數(shù)據(jù)庫提供的函數(shù)進(jìn)行分區(qū).
create table t(
value int
)engine=InnoDB
partition by KEY(value)
partitions 4;
5). COLUMNS分區(qū)
? 前面介紹的分區(qū)都有局限性,分區(qū)的依據(jù)必須為整數(shù),否則需要通過函數(shù)來轉(zhuǎn)換.
? MySQL 5.5版本開始支持COLUMNS分區(qū),可視為RANGE分區(qū)和LIST分區(qū)的進(jìn)化,可以直接使用非整型的數(shù)據(jù)(日期,字符,不支持float)進(jìn)行分區(qū).
? 對LIST分區(qū)的加強(qiáng)主要指對字符串進(jìn)行分類.
? 在RANGE或者LIST后加上COLUMNS即可去掉轉(zhuǎn)化函數(shù).
create table t_date(
value datetime
)engine=InnoDB
partition by RANGE COLUMNS (value)(
partition p2008 values less than (2009),
partition p2009 values less than (2010),
partition pfuture values less than maxvalue
);
(3). 子分區(qū)
? 子分區(qū)是在分區(qū)的基礎(chǔ)上在進(jìn)行分區(qū),MySQL數(shù)據(jù)庫允許在RANGE和LIST分區(qū)上在進(jìn)行一次HASH或KEY分區(qū).語法如下:
create table t(
value int
)engine=InnoDB
partition by RANGE(value)
subpartition by HASH(value)(
partition p0 values less than (10)(
subpartition s0,
subpartition s0
),
partition p1 values less than (20)(
subpartition s2,
subpartition s3
),
partition p3 values less than maxvalue(
subpartition s4,
subpartition s5
)
);
注意事項:
- 每個分區(qū)的子分區(qū)數(shù)量必須一致
- 只要一個分區(qū)定義了子分區(qū),那么所有分區(qū)都要有子分區(qū)
- 每個子分區(qū)必須有名字,且唯一
(4). 分區(qū)中的NULL值
? MySQL數(shù)據(jù)庫的分區(qū)視NULL為無窮小的值.例如RANGE分區(qū)會將NULL值插入最左側(cè)最小的分區(qū).但在LIST分區(qū)中必須明確指出那個分區(qū)可以放置NULL值.HASH和KEY分區(qū)中,NULL的哈希結(jié)果總是為0.
(5). 分區(qū)和性能
? 數(shù)據(jù)庫應(yīng)用一般分為兩類:OLTP(在線事務(wù)處理,一般指高并發(fā)情況下的數(shù)據(jù)庫設(shè)計)和OLAP(在線分析處理,指多樣化查詢的數(shù)據(jù)庫設(shè)計).對于OLAP的應(yīng)用,分區(qū)可以很好的提高效率,但對于OLTP的應(yīng)用,分區(qū)很可能導(dǎo)致增加IO操作,而非提高效率.
(6). 在表和分區(qū)之間交換數(shù)據(jù)
? MySQL 5.6開始支持分區(qū)或者子分區(qū)中的數(shù)據(jù)與另一個非分區(qū)表中的數(shù)據(jù)進(jìn)行交換.
alter table 分區(qū)表名 exchange partition 分區(qū)表中的分區(qū)名 with table 非分區(qū)表