mysql分区功能详细介绍,以及实例。
一,什么是数据库分区
前段时间写过一篇关于mysql分表的的文章,下面来说一下什么是数据库分区,以mysql为例。mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的。如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样呢,我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,这个时候,我们可以把数据分配到不同的磁盘里面去。
分区的二种方式
1,横向分区
什么是横向分区呢?就是横着来分区了,举例来说明一下,假如有100W条数据,分成十份,前10W条数据放到第一个分区,第二个10W条数据放到第二个分区,依此类推。也就是把表分成了十分,根用merge来分表,有点像哦。取出一条数据的时候,这条数据包含了表结构中的所有字段,也就是说横向分区,并没有改变表的结构。
2,纵向分区
什么是纵向分区呢?就是竖来分区了,举例来说明,在设计用户表的时候,开始的时候没有考虑好,而把个人的所有信息都放到了一张表里面去,这样这个表里面就会有比较大的字段,如个人简介,而这些简介呢,也许不会有好多人去看,所以等到有人要看的时候,在去查找,分表的时候,可以把这样的大字段,分开来。
感觉数据库的分区好像是切苹果,到底是横着切呢,还是竖着切,根据个人喜好了,mysql提供的分区属于第一种,横向分区,并且细分成很多种方式。下面将举例说明一下。
二,mysql的分区
我觉着吧,mysql的分区只有一种方式,只不过运用不同的算法,規则将数据分配到不同的区块中而已。
1,mysql5.1及以上支持分区功能
安装安装的时候,我们就可以查看一下
查看复制打印?[root@BlackGhost mysql-5.1.50]# ./configure --help |grep -A 3 Partition === Partition Support ===Plugin Name: partition Description: MySQL Partitioning SupportSupports build: static Configurations: max, max-no-ndb查看复制打印?mysql> show variables like "%part%"; +-------------------+-------+| Variable_name | Value | +-------------------+-------+| have_partitioning | YES | +-------------------+-------+1 row in set (0.00 sec)查看复制打印?//创建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.MYD4.0K user#P#p0.MYI 4.0K user#P#p1.MYD4.0K user#P#p1.MYI 4.0K user#P#p2.MYD4.0K user#P#p2.MYI 4.0K user#P#p3.MYD4.0K user#P#p3.MYI 4.0K user#P#p4.MYD4.0K user#P#p4.MYI 12K user.frm4.0K user.par//取出数据 mysql> select count(id) as count from user;+-------+ | count |+-------+ | 25 |+-------+ 1 row in set (0.00 sec)//删除第四个分区mysql> alter table user drop partition p4; Query OK, 0 rows affected (0.11 sec)Records: 0 Duplicates: 0 Warnings: 0mysql> select count(id) as count from user; +-------+| count | +-------+| 11 | +-------+1 row in set (0.00 sec)//第四个区块已删除 [root@BlackGhost test]# ls |grep user |xargs du -sh4.0K user#P#p0.MYD 4.0K user#P#p0.MYI4.0K user#P#p1.MYD 4.0K user#P#p1.MYI4.0K user#P#p2.MYD 4.0K user#P#p2.MYI4.0K user#P#p3.MYD 4.0K user#P#p3.MYI12K user.frm 4.0K user.par 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 |+----------+ 1 row in set (0.00 sec)//删除一个分区mysql> alter table aa drop partition p2; Query OK, 0 rows affected (0.30 sec)Records: 0 Duplicates: 0 Warnings: 0//只有11条了,说明对现有的表分区成功了 mysql> select count(*) from aa;+----------+ | count(*) |+----------+ | 11 |+----------+ 1 row in set (0.00 sec)查看复制打印?//这种方式失败 mysql> CREATE TABLE IF NOT EXISTS `list_part` (-> `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', -> `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',-> `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称', -> `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0为男,1为女',-> PRIMARY KEY (`id`) -> ) 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//这种方式成功 mysql> CREATE TABLE IF NOT EXISTS `list_part` (-> `id` int(11) NOT NULL COMMENT '用户ID', -> `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',-> `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称', -> `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0为男,1为女'-> ) ENGINE=INNODB DEFAULT CHARSET=utf8 -> 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)-> ); Query OK, 0 rows affected (0.33 sec)查看复制打印?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',-> PRIMARY KEY (`id`) -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1-> PARTITION BY HASH(id) -> PARTITIONS 3;Query OK, 0 rows affected (0.06 sec)查看复制打印?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 '时间' -> ) ENGINE=INNODB DEFAULT CHARSET=utf8-> PARTITION BY LINEAR HASH(YEAR(create_time)) -> PARTITIONS 3;Query OK, 0 rows affected (0.07 sec)查看复制打印?mysql> CREATE TABLE IF NOT EXISTS `sub_part` ( -> `news_id` int(11) NOT NULL COMMENT '新闻ID',-> `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新闻内容', -> `u_id` int(11) NOT NULL DEFAULT 0s COMMENT '来源IP',-> `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '时间' -> ) ENGINE=INNODB DEFAULT CHARSET=utf8-> 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) -> );Query OK, 0 rows affected (0.07 sec)mysql> alter table user drop partition p4;查看复制打印?//range添加新分区 mysql> alter table user add partition(partition p4 values less than MAXVALUE);Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0//list添加新分区mysql> alter table list_part add partition(partition p4 values in (25,26,28)); Query OK, 0 rows affected (0.01 sec)Records: 0 Duplicates: 0 Warnings: 0//hash重新分区 mysql> alter table hash_part add partition partitions 4;Query OK, 0 rows affected (0.12 sec) Records: 0 Duplicates: 0 Warnings: 0//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) Records: 0 Duplicates: 0 Warnings: 0mysql> show create table sub1_part\G;*************************** 1. row *************************** Table: sub1_partCreate 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 '时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8!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))1 row in set (0.00 sec)查看复制打印?//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)Records: 0 Duplicates: 0 Warnings: 0//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 180