天天看點

Mysql分區表介紹

分區:

分區的功能不是在存儲引擎層實作的。是以不隻是InnoDB才支援分區。MyISAM、NDB都支援分區操作。

分區的過程是将一個表或者索引分解為多個更小、更可管理的部分。從邏輯上将,隻有一個表或者索引,但是在實體上這個表或索引可能由數十個實體分區組成。

每個分區都是獨立的對象,可以獨自處理,也可以作為一個更大對象的一部分進行處理。

MySQL隻支援水準分區,不支援垂直分區。

水準分區:将同一表中不同行的記錄配置設定到不同的實體檔案中。

垂直分區:将同一表中不同列的記錄配置設定到不同的實體檔案中。

MySQL資料庫的分區是局部分區索引。一個分區中既存放了資料又存放了索引。而全局分區索引指的是資料存放在各個分區中,但是所有資料的索引放在一個對象中。MySQL暫時還不支援全局分區索引。

檢視目前資料庫是否啟用了分區功能:

檢視目前MySQL上有哪些分區表:

MySQL資料庫支援以下幾種類型的分區:

RANGE分區

LIST分區

HASH分區

KEY分區

如下就是建立分區的表的方式:

> create table t4 (
col1 int null,
col2 date null,
col3 int null,
col4 int null,
key (col3)
) engine=InnoDB
partition BY HASH (col3)
partitions ;        -- 劃分成個分區
           
-rw-rw----  mariadb mariadb  -- : t4#P#p0.ibd
-rw-rw----  mariadb mariadb  -- : t4#P#p1.ibd
-rw-rw----  mariadb mariadb  -- : t4#P#p2.ibd
-rw-rw----  mariadb mariadb  -- : t4#P#p3.ibd
           

分區類型:

1 RANGE分區:

> create table t1 (id int)
partition by range(id)(
partition p0 values less than (),
partition p1 values less than ());
           

當資料小于10的時候,插入p0分區。大于等于10小于20時候,插入p1分區。

> INSERT INTO t1 SELECT ;
> INSERT INTO t1 SELECT ;
           

表實體檔案變成了下面這種:

-rw-rw----  mariadb mariadb  -- : t1#P#p0.ibd
-rw-rw----  mariadb mariadb  -- : t1#P#p1.ibd
           

從表面上,看不出來到底插入到什麼分區中了,可以用下面的指令檢視:

> SELECT * from information_schema.PARTITIONS where table_schema=database() and table_name='t1'\G

***************************[ . row ]***************************
TABLE_CATALOG                 | def
TABLE_SCHEMA                  | hellodb
TABLE_NAME                    | t1
PARTITION_NAME                | p0        # 這裡能看到是插入到p0分區的
SUBPARTITION_NAME             | None
PARTITION_ORDINAL_POSITION    | 1
SUBPARTITION_ORDINAL_POSITION | None
PARTITION_METHOD              | RANGE       # 這裡看得出是range分區類型
SUBPARTITION_METHOD           | None
PARTITION_EXPRESSION          | id
SUBPARTITION_EXPRESSION       | None
PARTITION_DESCRIPTION         | 10
TABLE_ROWS                    | 1           # 這個反映了該分區(這裡是p0)記錄的行數量。
AVG_ROW_LENGTH                | 16384
DATA_LENGTH                   | 16384
MAX_DATA_LENGTH               | None
INDEX_LENGTH                  | 0
DATA_FREE                     | 0
CREATE_TIME                   | None
UPDATE_TIME                   | None
CHECK_TIME                    | None
CHECKSUM                      | None
PARTITION_COMMENT             | 
NODEGROUP                     | default
TABLESPACE_NAME               | None
***************************[ . row ]***************************
TABLE_CATALOG                 | def
TABLE_SCHEMA                  | hellodb
TABLE_NAME                    | t1
PARTITION_NAME                | p1        # 這裡能看到是插入到p1分區的
SUBPARTITION_NAME             | None
PARTITION_ORDINAL_POSITION    | 2
SUBPARTITION_ORDINAL_POSITION | None
PARTITION_METHOD              | RANGE
SUBPARTITION_METHOD           | None
PARTITION_EXPRESSION          | id
SUBPARTITION_EXPRESSION       | None
PARTITION_DESCRIPTION         | 20
TABLE_ROWS                    | 1
AVG_ROW_LENGTH                | 16384
DATA_LENGTH                   | 16384
MAX_DATA_LENGTH               | None
INDEX_LENGTH                  | 0
DATA_FREE                     | 0
CREATE_TIME                   | None
UPDATE_TIME                   | None
CHECK_TIME                    | None
CHECKSUM                      | None
PARTITION_COMMENT             | 
NODEGROUP                     | default
TABLESPACE_NAME               | None
           

INSERT INTO t1 SELECT 32; # 這個插入會報錯,因為我們上面定義的分區,并不包含這個區間。

對此,要允許插入大數的話,可以修改下表:

ALTER TABLE t1 add partition( partition p2 values less than (30)); 或者 ALTER TABLE t1 add partition( partition p2 values less than maxvalue );

這下我們插入大數值的話,也不會報錯了。

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

> CREATE TABLE sales (
money INT UNSIGNED NOT NULL,
`date` DATETIME
) ENGINE=INNODB
PARTITION BY RANGE (YEAR(DATE)) (
PARTITION p2008 VALUES LESS THAN (),
PARTITION p2009 VALUES LESS THAN (),
PARTITION p2010 VALUES LESS THAN ()
);

> INSERT INTO sales SELECT ,'2008-04-20';
> INSERT INTO sales SELECT ,'2009-01-25';
> INSERT INTO sales SELECT ,'2010-12-20';
           

這樣的話,不同年份的資料就插入到不同的分區中,便于對sales這張表進行管理。

如果要删除2008年的資料,不需要執行delete from sales where date>=’2008-01-01’ and date<=’2008-12-31’; 隻要删除2008年資料所在的分區即可:

> alter table sales drop partition p2008;
           

分區的另一個好處是:

加快某些查詢,例如我們隻要查詢2009年整年的銷售額,如下即可:

> explain partitions select * from sales where date >='2009-01-01' and date <='2009-12-31'\G
***************************[ 1. row ]***************************
id            | 1
select_type   | SIMPLE
table         | sales
partitions    | p2009    # 隻去p2009這個分區去搜尋
type          | ALL
possible_keys | None
key           | None
key_len       | None
ref           | None
rows          | 2
Extra         | Using where
           

最常用的就是range分區。

但是注意:如果分區鍵是timestamp類型的,則必須用UNIX_TIMESTAMP轉換下。如下例子:

ALTER TABLE `order_his_tmp` drop primary key, add primary key(id,order_time);   去掉原先的主鍵,加一個帶分區ID的主鍵。

ALTER TABLE `order_his_tmp` PARTITION BY RANGE (UNIX_TIMESTAMP (order_time)) ( 
 PARTITION  p201508  VALUES LESS THAN  (UNIX_TIMESTAMP('2015-09-01')) ,
 PARTITION  p201509  VALUES LESS THAN  (UNIX_TIMESTAMP('2015-10-01')) ,
 PARTITION  P201510  VALUES LESS THAN  (UNIX_TIMESTAMP('2015-11-01')) ,
 PARTITION  P201511  VALUES LESS THAN  (UNIX_TIMESTAMP('2015-12-01')) ,
 PARTITION  P201512  VALUES LESS THAN  (UNIX_TIMESTAMP('2016-01-01')) ,
 PARTITION  P201601  VALUES LESS THAN  (UNIX_TIMESTAMP('2016-02-01')) ,
 PARTITION  P201602  VALUES LESS THAN  (UNIX_TIMESTAMP('2016-03-01')) );
           

對于分區鍵是DATETIME的,要用TO_DAYS()函數操作,如下例子:

> CREATE TABLE sales(
money int unsigned not null,
date datetime)
partition by range (TO_DAYS(date)) (
partition p201001 values less than (TO_DAYS('2010-02-01')), 
partition p201002 values less than (TO_DAYS('2010-03-01')), 
partition p201003 values less than (TO_DAYS('2010-04-01'))
);
           

2 LIST分區【不多見】:

和range分區類似,隻是分區列的值是散列的,而非連續的。

> CREATE TABLE t (
a INT,
b INT) ENGINE INNODB
PARTITION BY LIST(b) (
PARTITION p0 VALUES IN (,,,,),
PARTITION p1 VALUES IN (,,,)
);
           

注意:list分區中使用的是VALUES IN 這種格式。

> insert into t select ,;
> insert into t select ,;  執行這行插入語句會報錯,因為按照LIST(b)劃分的話,不在上述的LIST裡面。
> insert into t select ,;  執行這行插入語句會報錯,因為按照LIST(b)劃分的話,不在上述的LIST裡面。
> insert into t select ,;

> SELECT table_name,partition_name,table_rows from information_schema.Partitions where table_name='t' and table_schema=DATABASE()\G
           

結果如下:

***************************[ 1. row ]***************************
table_name     | t
partition_name | p0
table_rows     | 1
***************************[ 2. row ]***************************
table_name     | t
partition_name | p1
table_rows     | 2   表示p1分區有2行資料
           

注意:

InnoDB和MyISAM在遇到一次性插入多條資料中出現分區未定義錯誤的時候處理方式是不同的。

InnoDB會把整個SQL語句當做一個事務,隻要有錯誤,就完全不執行。而MyISAM則會将錯誤之前的sql都執行成功。

3 HASH分區:

HASH分區的目的是将資料均勻地分布到預先定義的各個分區中,保證各分區的資料數量大緻都是一樣的。

在RANGE和LIST分區中,必須明确指定一個給定的列值或列值集合應該儲存在哪個分區中。在HASH分區中,MySQL自動完成這些工作,用于所要做的隻是基于将要進行哈希分區的列值指定一個列值或表達式,以及指定備份去的表将要被分割成的分區數量。

要使用HASH分區來分割一個表,要在CREATE TABLE語句上添加一個 PARTITION BY HASH(expr) 子句,其中expr是一個傳回一個整數的表達式。它可以僅僅是字段類型為MySQL整型的列名。

此外,使用者可以自定義分區的數量,隻要加上參數PARTITIONS xxx即可。如下:

> create table t_hash (
a int,
b datetime
) engine innodb
PARTITION BY HASH (YEAR(b))
PARTITIONS ;
> INSERT INTO t_hash VALUES (,'2013-03-11 12:21:22');
           

上面這條插入的話,實際上要執行MOD(2013,4)取餘數,得出這行資料存放在哪個分區中。

> SELECT table_name,partition_name,table_rows FROM information_schema.`PARTITIONS` WHERE table_schema=DATABASE() AND table_name='t_hash' ;
結果如下:
+------------+----------------+------------+
| table_name | partition_name | table_rows |
+------------+----------------+------------+
| t_hash     | p0             |           |  
| t_hash     | p1             |           |  # 可以看到p1插入了條資料,因為年除以,餘數是。是以年都資料都落在p1分區
| t_hash     | p2             |           |
| t_hash     | p3             |           |
+------------+----------------+------------+
           

4 LINEAR HASH分區:(線性hash)

mysql還支援這種複雜的分區算法。文法和HASH分區類似,隻是将關鍵字HASH改成了LINEAR HASH。

如下:

> CREATE TABLE t_l_hash (
a INT,
b DATETIME
) ENGINE INNODB
PARTITION BY LINEAR HASH(YEAR(b))
PARTITIONS ;
           

取大于分區數量4的下一個2的幂值V,V=POWER(2,CEILING(LOG(2,num)))=4

所在分區N=YEAR(‘2010-04-01’)&(V-1)=2.

LINEAR HASH分區的

優點:

增加、删除、合并和拆分分區将變得更加快捷,有利于處理含有大量資料的表。

缺點:

與使用HASH分區得到的資料分布相比,各個分區間資料的分布可能不大均衡。

> INSERT INTO t_l_hash VALUE (2,'2014-04-23 12:23:33');

> SELECT table_name,partition_name,table_rows
FROM information_schema.`PARTITIONS`
WHERE table_schema=DATABASE() AND table_name='t_l_hash'\G

結果如下:

***************************[ 1. row ]***************************
table_name     | t_l_hash
partition_name | p0
table_rows     | 1
***************************[ 2. row ]***************************
table_name     | t_l_hash
partition_name | p1
table_rows     | 0
***************************[ 3. row ]***************************
table_name     | t_l_hash
partition_name | p2
table_rows     | 1
***************************[ 4. row ]***************************
table_name     | t_l_hash
partition_name | p3
table_rows     | 0
           

5 KEY分區:

和HASH分區類似,不同之處在于HASH分區使用使用者定義的函數進行分區,KEY分區使用MySQL資料庫提供的函數進行分區。

對于NDB Cluster引擎,MySQL資料庫使用MD5函數來分區;對于其他引擎,使用MySQL内部的哈希函數來分區。

> CREATE TABLE t_key (
a INT,
b DATETIME
) ENGINE INNODB
PARTITION BY KEY(b)
PARTITIONS  ;
           

6 COLUMNS分區【很常用】:

前面的幾種分區都是有條件限制的。條件是:必須是整型,如果不是整型,那麼也必須是可以通過函數轉換為整型的,如YEAR()、TO_DAYS()、MONTH()等函數。

MySQL5.5版本開始支援的COLUMNS分區,可視為RANGE分區和LIST分區的一種進化。

COLUMNS分區看直接使用非整型的資料進行分區,分區根據類型直接比較而得,不需要轉換為整型。

此外,COLUMNS分區可以對多個列的值進行分區。

COLUMNS分區支援以下的資料類型:

1 所有的整型類型

支援:INT、SMALLINT、TINYINT、BIGINT。不支援:FLOAT和DECIMAL

2 日期類型 【常用】

支援 DATE、DATETIME

3 字元串類型

支援 CAHR、VARCHAR、BINARY、VARBINARY。不支援BLOB和TEXT

> CREATE TABLE t_columns_range (
a INT,
b DATETIME
)ENGINE INNODB
PARTITION BY  RANGE COLUMNS (B) (
PARTITION p0 VALUES LESS THAN ('2009-01-01'),
PARTITION p1 VALUES LESS THAN ('2010-01-01')
);
           
注意和range分區的SQL語句差别!!(分區範圍裡不用函數處理列了)

對于現有的表改成分區表:

ALTER TABLE `tb_detail` drop primary key ,add primary key (id, bill_date);

ALTER TABLE `tb_detail` PARTITION BY RANGE COLUMNS (bill_date)   (   
PARTITION  p201509  VALUES LESS THAN  ('2015-10-01') ,   
PARTITION  P201510  VALUES LESS THAN  ('2015-11-01') ,
PARTITION  P201511  VALUES LESS THAN  ('2015-12-01') ,
PARTITION  P201512  VALUES LESS THAN  ('2016-01-01') ,
PARTITION  P201601  VALUES LESS THAN  ('2016-02-01') ,
PARTITION  P201602  VALUES LESS THAN  ('2016-03-01') ,
PARTITION  P201603  VALUES LESS THAN  ('2016-04-01') ,
PARTITION  P201604  VALUES LESS THAN  ('2016-05-01') );
           

對于RANGE COLUMNS分區,可以使用多個列進行分區,如:

> CREATE TABLE rcx (
a INT,
b INT,
c CHAR(),
d INT
)ENGINE INNODB
PARTITION BY  RANGE COLUMNS (a,b,c) (
PARTITION p0 VALUES LESS THAN (,,'ggg'),
PARTITION p1 VALUES LESS THAN (,,'mmm'),
PARTITION p2 VALUES LESS THAN (,,'sss'),
PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
);
           

MySQL5.5開始支援COLUMNS分區。對于之前的RANGE和LIST分區。使用者可以用RANGE COLUMNS和LIST COLUMNS分區進行很好的代替。

手工添加分區:

CREATE TABLE `t10` (
 `a` int() NOT NULL AUTO_INCREMENT,
 `b` int() DEFAULT NULL,
 PRIMARY KEY (`a`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8
PARTITION BY RANGE  COLUMNS(a)
(PARTITION p0 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p4 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p5 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p6 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p7 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p8 VALUES LESS THAN () ENGINE = InnoDB,
PARTITION p9 VALUES LESS THAN () ENGINE = InnoDB );  ---> 注意這裡最後一個分區範圍沒有像上面其他案例那樣寫死
           

後期可以使用 ALTER TABLE t10 ADD PARTITION (PARTITION p10 VALUES LESS THAN (110)); 這樣就可以加一個分區了。

子分區:

子分區(subpartitioning)是在分區的基礎上在進行分區,有時也稱這種分區為複合分區(composite partitioning)。

MySQL資料庫允許在RANGE和LIST分區上再進行HASH或KEY的子分區。如:

> CREATE TABLE ts (
a INT,
b DATE
) ENGINE=INNODB
PARTITION BY RANGE(YEAR(b))
SUBPARTITION BY HASH(TO_DAYS(b))
SUBPARTITIONS  (
PARTITION p0 VALUES LESS THAN (),
PARTITION p1 VALUES LESS THAN (),
PARTITION p2 VALUES LESS THAN MAXVALUE);
           

在實體檔案上表示形式如下:

-rw-rw----  mariadb mariadb    -- : ts.frm
-rw-rw----  mariadb mariadb    -- : ts.par
-rw-rw----  mariadb mariadb  -- : ts#P#p0#SP#p0sp0.ibd
-rw-rw----  mariadb mariadb  -- : ts#P#p0#SP#p0sp1.ibd
-rw-rw----  mariadb mariadb  -- : ts#P#p1#SP#p1sp0.ibd
-rw-rw----  mariadb mariadb  -- : ts#P#p1#SP#p1sp1.ibd
-rw-rw----  mariadb mariadb  -- : ts#P#p2#SP#p2sp0.ibd
-rw-rw----  mariadb mariadb  -- : ts#P#p2#SP#p2sp1.ibd
           

先進行range分區(p0\p1\p2),再進行hash分區(sp0\sp1)。(合計共3*2=6個分區),上面實體檔案上面也能看出來是6個分區。

子分區的建立需要注意下面問題:

1、每個子分區的數量必須相同。

2、要在一個分區表的任何分區上使用SUBPARTITION來明确定義任何子分區,就必須定義所有的子分區。

3、每個SUBPARTITION子句必須包括子分區的一個名字。

4、子分區的名字必須是唯一的。

子分區可以用于特别大的表,在多個磁盤間分别配置設定資料和索引。

如下為6個磁盤的分區執行個體(InnoDB引擎):

> CREATE TABLE ts (
a INT,
b DATE)ENGINE INNODB
PARTITION BY RANGE(YEAR(b))
SUBPARTITION BY HASH(TO_DAYS(b)) (
PARTITION p0 VALUES LESS THAN () (
SUBPARTITION s0
DATA DIRECTORY = '/disk0/data'
INDEX DIRECTORY = '/disk0/idx',
SUBPARTITION s1
DATA DIRECTORY = '/disk1/data'
INDEX DIRECTORY = '/disk1/idx'
),
PARTITION p1 VALUES LESS THAN () (
SUBPARTITION s2
DATA DIRECTORY = '/disk2/data'
INDEX DIRECTORY = '/disk2/idx',
SUBPARTITION s3
DATA DIRECTORY = '/disk3/data'
INDEX DIRECTORY = '/disk3/idx'
),
PARTITION p2 VALUES LESS THAN MAXVALUE (
SUBPARTITION s4
DATA DIRECTORY = '/disk4/data'
INDEX DIRECTORY = '/disk4/idx',
SUBPARTITION s5
DATA DIRECTORY = '/disk5/data'
INDEX DIRECTORY = '/disk5/idx'
)
);
           

分區中的NULL值:

MySQL允許對NULL值做分區。但是處理的方法與其他資料庫完全不同。

MySQL資料庫的分區總是視NULL值小于任何的一個非NULL值,這和MySQL資料庫中處理NULL值的ORDER BY操作是一樣的。是以對于不同的分區類型,MySQL資料庫對于NULL值的處理也是各不相同。

1、RANGE分區中使用NULL值:

> CREATE table t_range(
     a int,
     b int)
     partition by range(b) (
     partition p0 VALUES less than (),
     partition p1 VALUES less than (),
     partition p2 values less than maxvalue);

   > insert into t_range select ,;
   > insert into t_range select ,null;

   > SELECT table_name,partition_name,table_rows
FROM information_schema.`PARTITIONS`
WHERE table_schema=DATABASE() AND table_name='t_range';
           

結果如下:

+------------+----------------+------------+
| table_name | partition_name | table_rows |
+------------+----------------+------------+
| t_range    | p0             |          2 |
| t_range    | p1             |          0 |
| t_range    | p2             |          0 |
+------------+----------------+------------+
           

可以看到插入的資料都放到了p0分區。

也就是說在RANGE分區下,NULL值會放入最左邊的分區中。

另外,如果删除了p0分區,删除的将是小于10的記錄和NULL值的記錄,這點非常重要。

> alter table t_range drop partition p0;
> SELECT * from t_range;  可以看到下圖的表已經為空值了
+-----+-----+
| a   | b   |
|-----+-----|
+-----+-----+
           

2、LIST分區下使用NULL值,必須顯式的指出哪個分區中放入NULL值,否則會報錯。

如下寫法才能允許插入NULL值。

> CREATE table t_list (
a int,
b int)
partition by list(b) (
partition p0 values in (,,,,,NULL),    # 注意必須顯式的指出NULL插入到那個分區才行
partition p1 VALUES in (,,,,));

> INSERT INTO t_list SELECT ,;
> INSERT INTO t_list SELECT ,null;

> SELECT table_name,partition_name,table_rows
IFROM information_schema.`PARTITIONS`
WHERE table_schema=DATABASE() AND table_name='t_list'\G
           

結果如下:

***************************[ 1. row ]***************************
table_name     | t_list
partition_name | p0
table_rows     | 1
***************************[ 2. row ]***************************
table_name     | t_list
partition_name | p1
table_rows     | 1
           

3、HASH和KEY分區對于NULL的處理方式和RANGE分區、LIST分區不一樣。

任何分區函數都會将含有NULL值的記錄傳回為0。【傳回0的說明是存放在第一個分區中】

> create table t_hash (
a int,
b int ) engine=innodb
partition by hash(b)
partitions ;

> INSERT INTO t_hash SELECT ,null;
> INSERT INTO t_hash SELECT ,;

 > SELECT table_name,partition_name,table_rows
FROM information_schema.`PARTITIONS`
WHERE table_schema=DATABASE() AND table_name='t_hash'\G
           

結果如下:

***************************[ 1. row ]***************************
table_name     | t_hash
partition_name | p0
table_rows     | 1
***************************[ 2. row ]***************************
table_name     | t_hash
partition_name | p1
table_rows     | 0
***************************[ 3. row ]***************************
table_name     | t_hash
partition_name | p2
table_rows     | 1
***************************[ 4. row ]***************************
table_name     | t_hash
partition_name | p3
table_rows     | 0
           

在表和分區之間交換資料:

mysql5.6開始支援 ALTER TABLE … EXCHANGE PARTITION 文法。該語句允許分區或子分區的資料與另一個非分區的表中的資料進行交換。

如果非分區表中的資料為空,那麼相當于分區中的資料移動到非分區表中。

若分區表中的資料為空,則相當于将外部表中的資料導入到分區中。

要使用ALTER TABLE … EXCHANGE語句,必須滿足下面的條件:

1 要交換的表需要和分區表有相同的表結構,但是不能有分區。

2 在非分區表中的資料必須在交換的分區定義内。

3 被交換的表中不能含有外鍵,或者其他的表含有對該表的外鍵引用。

4 使用者除了需要alter、insert、create權限外,還需要drop的權限。

此外,有2個小的細節要注意:

1、使用該語句時,不會觸發交換表和被交換表上的觸發器。

2、AUTO_INCREMENT列将被重置。

例子:

建立一個含有RANGE分區的表e,并填充資料:

> CREATE TABLE e (
id INT NOT NULL,
fname VARCHAR(),
lname VARCHAR()
)
PARTITION BY RANGE (id) (
PARTITION p0 VALUES LESS THAN (),
PARTITION p1 VALUES LESS THAN (),
PARTITION p2 VALUES LESS THAN (),
PARTITION p3 VALUES LESS THAN (MAXVALUE)
);

> INSERT INTO e VALUES
(,'zhang','san'),
(,'jim','ling'),
(,'wang','wu'),
(,'li','si');
           

然後建立交換表e2。結構和表e一樣,但是表e2中不含有分區。

> CREATE TABLE e2 (
id INT NOT NULL,
fname VARCHAR(),
lname VARCHAR()
); 
           

或者create table e2 like e; alter table e2 remove partitioning; 即可建立相同表結構的不帶分區參數的表e2

觀察分區表的中的資料:

> SELECT partition_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='e';
+------------------+--------------+
| partition_NAME   |   TABLE_ROWS |
|------------------+--------------|
| p0               |            1 |
| p1               |            0 |
| p2               |            0 |
| p3               |            3 |
+------------------+--------------+

> SELECT partition_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='e2';  可以看到e2表暫時是空的
           

使用alter table指令交換資料:

> ALTER TABLE e exchange PARTITION p0 WITH TABLE e2;  将表e的分區p0中的資料移動到表e2中。
           

再次檢視表e中分區的資料,可以看到p0中已經沒有資料了。

> SELECT partition_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='e';
+------------------+--------------+
| partition_NAME   |   TABLE_ROWS |
|------------------+--------------|
| p0               |            0 |
| p1               |            0 |
| p2               |            0 |
| p3               |            3 |
+------------------+--------------+

> SELECT * from e2;   檢視e2表,可以看到多了一條資料,就是從e交換而來的。
+------+---------+---------+
|   id | fname   | lname   |
|------+---------+---------|
|   33 | zhang   | san     |
+------+---------+---------+
           

轉自:http://blog.51cto.com/lee90/1955758

繼續閱讀