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