天天看點

mysql分區

分區的二種方式

1,橫向分區

什麼是橫向分區呢?就是橫着來分區了,舉例來說明一下,假如有100w條資料,分成十份,前10w條資料放到第一個分區,第二個10w條資料放到第二個分區,依此類推。也就是把表分成了十分,根用merge來分表,有點像哦。取出一條資料的時候,這條資料包含了表結構中的所有字段,也就是說橫向分區,并沒有改變表的結構。

mysql分區

alter table `yl_hospital_url` partition by range(id) (  

partition `p0` values less than (100000) ,   

partition `p1` values less than (200000) ,   

partition `p2` values less than (300000) ,   

partition `p3` values less than (400000) ,   

partition `p4` values less than (500000) ,   

partition `p5` values less than (600000) ,   

partition `p6` values less than (700000) ,  

partition `p6` values less than (700000) ,   

partition `p7` values less than (maxvalue)   

) ;  

 分區前查詢速度

mysql分區

 分區後查詢速度

mysql分區

二,mysql的分區

1,mysql5.1及以上支援分區功能

安裝安裝的時候,我們就可以檢視一下

mysql分區

[root@blackghost mysql-5.1.50]# ./configure --help |grep -a 3 partition  

 === partition support ===  

 plugin name:      partition  

 description:      mysql partitioning support  

 supports build:   static  

 configurations:   max, max-no-ndb  

 檢視一下,如果發現有上面這個東西,說明他是支援分區的,預設是打開的。如果你已經安裝過了mysql的話

mysql分區

mysql> show variables like "%part%";  

+-------------------+-------+  

| variable_name     | value |  

| have_partitioning | yes   |  

1 row in set (0.00 sec)  

 檢視一下變量,如果支援的話,會有上面的提示的。

2range分區

按照range分區的表是通過如下一種方式進行分區的,每個分區包含那些分區表達式的值位于一個給定的連續區間内的行

mysql分區

//建立range分區表  

mysql> create table if not exists `user` (  

 ->   `id` int(11) not null auto_increment comment '使用者id',  

 ->   `name` varchar(50) not null default '' comment '名稱',  

 ->   `sex` int(1) not null default '0' comment '0為男,1為女',  

 ->   primary key (`id`)  

 -> ) engine=myisam  default charset=utf8 auto_increment=1  

 -> partition by range (id) (  

 ->     partition p0 values less than (3),  

 ->     partition p1 values less than (6),  

 ->     partition p2 values less than (9),  

 ->     partition p3 values less than (12),  

 ->     partition p4 values less than maxvalue  

 -> );  

query ok, 0 rows affected (0.13 sec)  

//插入一些資料  

mysql> insert into `test`.`user` (`name` ,`sex`)values ('tank', '0')  

 -> ,('zhang',1),('ying',1),('張',1),('映',0),('test1',1),('tank2',1)  

 -> ,('tank1',1),('test2',1),('test3',1),('test4',1),('test5',1),('tank3',1)  

 -> ,('tank4',1),('tank5',1),('tank6',1),('tank7',1),('tank8',1),('tank9',1)  

 -> ,('tank10',1),('tank11',1),('tank12',1),('tank13',1),('tank21',1),('tank42',1);  

query ok, 25 rows affected (0.05 sec)  

records: 25  duplicates: 0  warnings: 0  

//到存放資料庫表檔案的地方看一下,my.cnf裡面有配置,datadir後面就是  

[root@blackghost test]# ls |grep user |xargs du -sh  

4.0k    user#p#p0.myd  

4.0k    user#p#p0.myi  

4.0k    user#p#p1.myd  

4.0k    user#p#p1.myi  

4.0k    user#p#p2.myd  

4.0k    user#p#p2.myi  

4.0k    user#p#p3.myd  

4.0k    user#p#p3.myi  

4.0k    user#p#p4.myd  

4.0k    user#p#p4.myi  

12k    user.frm  

4.0k    user.par  

//取出資料  

mysql> select count(id) as count from user;  

+-------+  

| count |  

|    25 |  

//删除第四個分區  

mysql> alter table user drop partition p4;  

query ok, 0 rows affected (0.11 sec)  

records: 0  duplicates: 0  warnings: 0  

/**存放在分區裡面的資料丢失了,第四個分區裡面有14條資料,剩下的3個分區 

隻有11條資料,但是統計出來的檔案大小都是4.0k,從這兒我們可以看出分區的 

最小區塊是4k 

*/  

|    11 |  

//第四個區塊已删除  

/*可以對現有表進行分區,并且會按規則自動的将表中的資料配置設定相應的分區 

中,這樣就比較好了,可以省去很多事情,看下面的操作*/  

mysql> alter table aa partition by range(id)  

 -> (partition p1 values less than (1),  

 -> partition p2 values less than (5),  

 -> partition p3 values less than maxvalue);  

query ok, 15 rows affected (0.21 sec)   //對15資料進行分區  

records: 15  duplicates: 0  warnings: 0  

//總共有15條  

mysql> select count(*) from aa;  

+----------+  

| count(*) |  

|       15 |  

//删除一個分區  

mysql> alter table aa drop partition p2;  

query ok, 0 rows affected (0.30 sec)  

//隻有11條了,說明對現有的表分區成功了  

|       11 |  

1 row in set (0.00 sec)   

3,list分區

list分區中每個分區的定義和選擇是基于某列的值從屬于一個值清單集中的一個值,而range分 區是從屬于一個連續區間值的集合。

mysql分區

//這種方式失敗  

mysql> create table if not exists `list_part` (  

 ->   `province_id` int(2) not null default 0 comment '省',  

 -> ) engine=innodb  default charset=utf8 auto_increment=1  

 -> partition by list (province_id) (  

 ->     partition p0 values in (1,2,3,4,5,6,7,8),  

 ->     partition p1 values in (9,10,11,12,16,21),  

 ->     partition p2 values in (13,14,15,19),  

 ->     partition p3 values in (17,18,20,22,23,24)  

error 1503 (hy000): a primary key must include all columns in the table's partitioning function  

//這種方式成功  

 ->   `id` int(11) not null  comment '使用者id',  

 ->   `sex` int(1) not null default '0' comment '0為男,1為女'  

 -> ) engine=innodb  default charset=utf8  

query ok, 0 rows affected (0.33 sec)  

上面的這個建立list分區時,如果有主銉的話,分區時主鍵必須在其中,不然就會報錯。如果我不用主鍵,分區就建立成功了,一般情況下,一個張表肯定會有一個主鍵,這算是一個分區的局限性吧。

如果對資料進行測試,請參考range分區的測試來操作

4,hash分區

hash分區主要用來確定資料在預先确定數目的分區中平均分布,你所要做的隻是基于将要被哈希的列值指定一個列值或表達式,以 及指定被分區的表将要被分割成的分區數量。

mysql分區

mysql> create table if not exists `hash_part` (  

 ->   `id` int(11) not null auto_increment comment '評論id',  

 ->   `comment` varchar(1000) not null default '' comment '評論',  

 ->   `ip` varchar(25) not null default '' comment '來源ip',  

 -> partition by hash(id)  

 -> partitions 3;  

query ok, 0 rows affected (0.06 sec)  

測試請參考range分區的操作

5,key分區

按照key進行分區類似于按照hash分區,除了hash分區使用的使用者定義的表達式,而key分區的 哈希函數是由mysql 伺服器提供。

mysql分區

mysql> create table if not exists `key_part` (  

 ->   `news_id` int(11) not null  comment '新聞id',  

 ->   `content` varchar(1000) not null default '' comment '新聞内容',  

 ->   `u_id` varchar(25) not null default '' comment '來源ip',  

 ->   `create_time` date not null default '0000-00-00 00:00:00' comment '時間'  

 -> partition by linear hash(year(create_time))  

query ok, 0 rows affected (0.07 sec)  

6,子分區

子分區是分區表中每個分區的再次分割,子分區既可以使用hash希分區,也可以使用key分區。這 也被稱為複合分區(composite partitioning )。

1,如果一個分區中建立了子分區,其他分區也要有子分區

2,如果建立了了分區,每個分區中的子分區數必有相同

3,同一分區内的子分區,名字不相同,不同分區内的子分區名子可以相同(5.1.50不适用)

mysql分區

mysql> create table if not exists `sub_part` (  

 ->   `u_id`  int(11) not null default 0s comment '來源ip',  

 -> partition by range(year(create_time))  

 -> subpartition by hash(to_days(create_time))(  

 -> partition p0 values less than (1990)(subpartition s0,subpartition s1,subpartition s2),  

 -> partition p1 values less than (2000)(subpartition s3,subpartition s4,subpartition good),  

 -> partition p2 values less than maxvalue(subpartition tank0,subpartition tank1,subpartition tank3)  

官方網站說不同分區内的子分區可以有相同的名字,但是mysql5.1.50卻不行會提示以下錯誤

error 1517 (hy000): duplicate partition name s1

7columns分區

應用場景:

商品銷售的日報表,年報表等

每天分一張表,表名用年月日每張表分24個分區,每個小時的資料分1個區.

mysql分區

create table `year_log` (  

  `id` int(11) default null,  

  `money` int(11) unsigned not null,  

  `date` datetime default null  

) engine=innodb default charset=utf8  

partition by range (year(date))  

(  

partition p2007 values less than (2008),  

partition p2008 values less than (2009),  

partition p2009 values less than maxvalue  

);  

create table `daily_log` (  

`id` int(11) not null,  

`sid` char(36) not null,  

`sname` char(20) default null,  

`date` datetime not null,  

primary key (`id`,`date`)  

partition by range columns(`date`)  

(partition p1 values less than ('2000-01-02'),  

partition p2 values less than ('2000-01-03'),  

partition p3 values less than ('2000-01-04'),  

partition p4 values less than ('2000-01-05'),  

partition p5 values less than ('2000-01-06'),  

partition p6 values less than ('2000-01-07'),  

partition p7 values less than ('2000-01-08'),  

partition p367 values less than (maxvalue));  

三,分區管理

1,删除分區

mysql分區

mysql> alter table user drop partition p4;    

 2,新增分區

mysql分區

//range添加新分區  

mysql> alter table user add partition(partition p4 values less than maxvalue);  

//list添加新分區  

mysql> alter table list_part add partition(partition p4 values in (25,26,28));  

query ok, 0 rows affected (0.01 sec)  

//hash重新分區  

mysql> alter table hash_part add partition partitions 4;  

query ok, 0 rows affected (0.12 sec)  

//key重新分區  

mysql> alter table key_part add partition partitions 4;  

query ok, 1 row affected (0.06 sec)    //有資料也會被重新配置設定  

records: 1  duplicates: 0  warnings: 0  

//子分區添加新分區,雖然我沒有指定子分區,但是系統會給子分區命名的  

mysql> alter table sub1_part add partition(partition p3 values less than maxvalue);  

query ok, 0 rows affected (0.02 sec)  

mysql> show create table sub1_part\g;  

*************************** 1. row ***************************  

 table: sub1_part  

create table: create table `sub1_part` (  

 `news_id` int(11) not null comment '新聞id',  

 `content` varchar(1000) not null default '' comment '新聞内容',  

 `u_id` varchar(25) not null default '' comment '來源ip',  

 `create_time` date not null default '0000-00-00' comment '時間'  

!50100 partition by range (year(create_time))  

subpartition by hash (to_days(create_time))  

(partition p0 values less than (1990)  

 (subpartition s0 engine = innodb,  

 subpartition s1 engine = innodb,  

 subpartition s2 engine = innodb),  

 partition p1 values less than (2000)  

 (subpartition s3 engine = innodb,  

 subpartition s4 engine = innodb,  

 subpartition good engine = innodb),  

 partition p2 values less than (3000)  

 (subpartition tank0 engine = innodb,  

 subpartition tank1 engine = innodb,  

 subpartition tank3 engine = innodb),  

 partition p3 values less than maxvalue  

 (subpartition p3sp0 engine = innodb,    //子分區的名子是自動生成的  

 subpartition p3sp1 engine = innodb,  

 subpartition p3sp2 engine = innodb))  

3,重新分區

mysql分區

//range重新分區  

mysql> alter table user reorganize partition p0,p1,p2,p3,p4 into (partition p0 values less than maxvalue);  

query ok, 11 rows affected (0.08 sec)  

records: 11  duplicates: 0  warnings: 0  

//list重新分區  

mysql> alter table list_part reorganize partition p0,p1,p2,p3,p4 into (partition p0 values in (1,2,3,4,5));  

query ok, 0 rows affected (0.28 sec)  

//hash和key分區不能用reorganize,官方網站說的很清楚  

mysql> alter table key_part reorganize partition coalesce partition 9;  

error 1064 (42000): you have an error in your sql syntax; check the manual that corresponds to your mysql server version for the right syntax to use near 'partition 9' at line 1  

四,分區優點

1,分區可以分在多個磁盤,存儲更大一點

2,根據查找條件,也就是where後面的條件,查找隻查找相應的分區不用全部查找了

3,進行大資料搜尋時可以進行并行處理。

4,跨多個磁盤來分散資料查詢,來獲得更大的查詢吞吐量