上海网务网络信息有限公司,2004年6月成立于上海,是上海市科委认证的高新技术企业。上海网务网络信息有限公司有着非凡的技术设计能力,自主研发了 ArthurXF  PHP开发框架,并在ArthurXF开发框架之上研发了BIWEB商务智能网站系统,BIWEB是经过不断的在各种大型项目中实践、总结、开发设计出来 的一个快速开发、简单易用的面向对象的企业应用级PHP MVC建站系统。BIWEB自2005年开源推出后,BIWEB网站系统在经历了多次重大版本升级之后,至2013年8月BIWEB推出webapp版 本,标志着BIWEB从电脑网站系统正式步入移动端应用系统时代。

上海网务公司在行业中发展多年,发现目前行业人才奇缺,招聘来的人员都需要再培训不能直接上岗,遂在上海、桂林、东莞等多地设立实习训练基地,为本公司及行业培养大量直接跟行业接轨的人才。上海网务公司设置的实训课程,直接按照工作岗位设立,完成实训课程即可就业。上海网务公司在行业内积累了大量人脉和口 碑,同行前来招聘络绎不绝,实训人员供不应求。如您有朋友想加入IT行业,请推荐来上海网务公司实训,上海网务公司对实训完成的学生可以解决上海就业。





BIWEB上海实训基地
1.上海市徐汇区漕溪路165号华谊党校1203室
2.上海黄浦区打浦路8号海华商厦2楼225室

BIWEB东莞实训基地
东莞市南城区西平二路弥珍道3栋306室
电话:0769-23889935

BIWEB桂林实训基地
桂林市雁山区果园村委旁二楼
电话:13367735767

实训基地加盟联系方式
联系人:肖飞
电话:13124812420
Tags:
一,什么是mysql分表,分区

什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法

什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上,具体请参考mysql分区功能详细介绍,以及实例

二,mysql分表和分区有什么区别呢

1,实现方式上

a),mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件,一个.MYD数据文件,.MYI索引文件,.frm表结构文件。

view sourceprint?1 [root@BlackGhost test]# ls |grep user    

2 alluser.MRG    

3 alluser.frm    

4 user1.MYD    

5 user1.MYI    

6 user1.frm    

7 user2.MYD    

8 user2.MYI    

9 user2.frm

简单说明一下,上面的分表呢是利用了merge存储引擎(分表的一种),alluser是总表,下面有二个分表,user1,user2。他们二个都是独立的表,取数据的时候,我们可以通过总表来取。这里总表是没有.MYD,.MYI这二个文件的,也就是说,总表他不是一张表,没有数据,数据都放在分表里面。我们来看看.MRG到底是什么东西

view sourceprint?1 [root@BlackGhost test]# cat alluser.MRG |more    

2 user1    

3 user2    

4 #INSERT_METHOD=LAST

从上面我们可以看出,alluser.MRG里面就存了一些分表的关系,以及插入数据的方式。可以把总表理解成一个外壳,或者是联接池。

b),分区不一样,一张大表进行分区后,他还是一张表,不会变成二张表,但是他存放数据的区块变多了。

view sourceprint?1 [root@BlackGhost test]# ls |grep aa    

2 aa#P#p1.MYD    

3 aa#P#p1.MYI    

4 aa#P#p3.MYD    

5 aa#P#p3.MYI    

6 aa.frm    

7 aa.par

从上面我们可以看出,aa这张表,分为二个区,p1和p3,本来是三个区,被我删了一个区。我们都知道一张表对应三个文件.MYD,.MYI,.frm。分区呢根据一定的规则把数据文件和索引文件进行了分割,还多出了一个.par文件,打开.par文件后你可以看出他记录了,这张表的分区信息,根分表中的.MRG有点像。分区后,还是一张,而不是多张表。

2,数据处理上

a),分表后,数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。看下面的例子:

select * from alluser where id=’12′表面上看,是对表alluser进行操作的,其实不是的。是对alluser里面的分表进行了操作。

b),分区呢,不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表呢,还是一张表。数据处理还是由自己来完成。

3,提高性能上

a),分表后,单表的并发能力提高了,磁盘I/O性能也提高了。并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出现高并发的话,总表可以根据不同的查询,将并发压力分到不同的小表里面。磁盘I/O性能怎么搞高了呢,本来一个非常大的.MYD文件现在也分摊到各个小表的.MYD中去了。

b),mysql提出了分区的概念,我觉得就想突破磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。

在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。

4),实现的难易度上

a),分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式根分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。

b),分区实现是比较简单的,建立分区表,根建平常的表没什么区别,并且对开代码端来说是透明的。

三,mysql分表和分区有什么联系呢

1,都能提高mysql的性高,在高并发状态下都有一个良好的表面。

2,分表和分区不矛盾,可以相互配合的,对于那些大访问量,并且表数据比较多的表,我们可以采取分表和分区结合的方式(如果merge这种分表方式,不能和分区配合的话,可以用其他的分表试),访问量不大,但是表数据很多的表,我们可以采取分区的方式等。

另附一段评价:
在以前,一种解决方案就是使用 MERGE

类型,这是一个非常方便的做饭。架构和程序基本上不用做改动,不过,它的缺点是显见的:

只能在相同结构的 MyISAM 表上使用
无法享受到 MyISAM 的全部功能,例如无法在 MERGE 类型上执行 FULLTEXT 搜索
它需要使用更多的文件描述符
读取索引更慢
这个时候,MySQL 5.1 中新增的分区(Partition)功能的优势也就很明显了:

与单个磁盘或文件系统分区相比,可以存储更多的数据
很容易就能删除不用或者过时的数据
一些查询可以得到极大的优化
涉及到 SUM()/COUNT() 等聚合函数时,可以并行进行
IO吞吐量更大
分区允许可以设置为任意大小的规则,跨文件系统分配单个表的多个部分。实际上,表的不同部分在不同的位置被存储为单独的表。

Tags: , ,
一,什么是数据库分区
前段时间写过一篇关于mysql分表的的文章,下面来说一下什么是数据库分区,以mysql为例。mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的。如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样呢,我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,这个时候,我们可以把数据分配到不同的磁盘里面去。

备注说明:上面是只对myisam存储引擎的,下面是innodb
innodb的数据库的物理文件结构为:

.frm文件

.ibd文件和.ibdata文件:

这两种文件都是存放innodb数据的文件,之所以用两种文件来存放innodb的数据,是因为innodb的数据存储方式能够通过配置来决定是使用共享表空间存放存储数据,还是用独享表空间存放存储数据。

独享表空间存储方式使用.ibd文件,并且每个表一个ibd文件

共享表空间存储方式使用.ibdata文件,所有表共同使用一个ibdata文件


分区的二种方式
1,横向分区
什么是横向分区呢?就是横着来分区了,举例来说明一下,假如有100W条数据,分成十份,前10W条数据放到第一个分区,第二个10W条数据放到第二个分区,依此类推。也就是把表分成了十分,根用merge来分表,有点像哦。取出一条数据的时候,这条数据包含了表结构中的所有字段,也就是说横向分区,并没有改变表的结构。

2,纵向分区
什么是纵向分区呢?就是竖来分区了,举例来说明,在设计用户表的时候,开始的时候没有考虑好,而把个人的所有信息都放到了一张表里面去,这样这个表里面就会有比较大的字段,如个人简介,而这些简介呢,也许不会有好多人去看,所以等到有人要看的时候,在去查找,分表的时候,可以把这样的大字段,分开来。

感觉数据库的分区好像是切苹果,到底是横着切呢,还是竖着切,根据个人喜好了,mysql提供的分区属于第一种,横向分区,并且细分成很多种方式。下面将举例说明一下。

二,mysql的分区
我觉着吧,mysql的分区只有一种方式,只不过运用不同的算法,規则将数据分配到不同的区块中而已。

1,mysql5.1及以上支持分区功能
安装安装的时候,我们就可以查看一下

view sourceprint?1 [root@BlackGhost mysql-5.1.50]# ./configure --help |grep -A 3 Partition  

2  === Partition Support ===  

3  Plugin Name:      partition  

4  Description:      MySQL Partitioning Support  

5  Supports build:   static

6  Configurations:   max, max-no-ndb

查看一下,如果发现有上面这个东西,说明他是支持分区的,默认是打开的。如果你已经安装过了mysql的话

view sourceprint?1 mysql> show variables like "%part%";  

2 +-------------------+-------+  

3 | Variable_name     | Value |  

4 +-------------------+-------+  

5 | have_partitioning | YES   |  

6 +-------------------+-------+  

7 1 row in set (0.00 sec)

查看一下变量,如果支持的话,会有上面的提示的。

2,range分区
按照RANGE分区的表是通过如下一种方式进行分区的,每个分区包含那些分区表达式的值位于一个给定的连续区间内的行

view sourceprint?1 //创建range分区表  

2 mysql> CREATE TABLE IF NOT EXISTS `user` (  

3  ->   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',  

4  ->   `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',  

5  ->   `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0为男,1为女',  

6  ->   PRIMARY KEY (`id`)  

7  -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1  

8  -> PARTITION BY RANGE (id) (  

9  ->     PARTITION p0 VALUES LESS THAN (3),  

10  ->     PARTITION p1 VALUES LESS THAN (6),  

11  ->     PARTITION p2 VALUES LESS THAN (9),  

12  ->     PARTITION p3 VALUES LESS THAN (12),  

13  ->     PARTITION p4 VALUES LESS THAN MAXVALUE  

14  -> );  

15 Query OK, 0 rows affected (0.13 sec)  

16    

17 //插入一些数据  

18 mysql> INSERT INTO `test`.`user` (`name` ,`sex`)VALUES ('tank', '0')  

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

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

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

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

23 Query OK, 25 rows affected (0.05 sec)  

24 Records: 25  Duplicates: 0  Warnings: 0  

25    

26 //到存放数据库表文件的地方看一下,my.cnf里面有配置,datadir后面就是  

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

28 4.0K    user#P#p0.MYD  

29 4.0K    user#P#p0.MYI  

30 4.0K    user#P#p1.MYD  

31 4.0K    user#P#p1.MYI  

32 4.0K    user#P#p2.MYD  

33 4.0K    user#P#p2.MYI  

34 4.0K    user#P#p3.MYD  

35 4.0K    user#P#p3.MYI  

36 4.0K    user#P#p4.MYD  

37 4.0K    user#P#p4.MYI  

38 12K    user.frm  

39 4.0K    user.par  

40    

41 //取出数据  

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

43 +-------+  

44 | count |  

45 +-------+  

46 |    25 |  

47 +-------+  

48 1 row in set (0.00 sec)  

49    

50 //删除第四个分区  

51 mysql> alter table user drop partition p4;  

52 Query OK, 0 rows affected (0.11 sec)  

53 Records: 0  Duplicates: 0  Warnings: 0  

54    

55 /**存放在分区里面的数据丢失了,第四个分区里面有14条数据,剩下的3个分区  

56 只有11条数据,但是统计出来的文件大小都是4.0K,从这儿我们可以看出分区的  

57 最小区块是4K  

58 */

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

60 +-------+  

61 | count |  

62 +-------+  

63 |    11 |  

64 +-------+  

65 1 row in set (0.00 sec)  

66    

67 //第四个区块已删除  

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

69 4.0K    user#P#p0.MYD  

70 4.0K    user#P#p0.MYI  

71 4.0K    user#P#p1.MYD  

72 4.0K    user#P#p1.MYI  

73 4.0K    user#P#p2.MYD  

74 4.0K    user#P#p2.MYI  

75 4.0K    user#P#p3.MYD  

76 4.0K    user#P#p3.MYI  

77 12K    user.frm  

78 4.0K    user.par  

79    

80 /*可以对现有表进行分区,并且会按規则自动的将表中的数据分配相应的分区  

81 中,这样就比较好了,可以省去很多事情,看下面的操作*/

82 mysql> alter table aa partition by RANGE(id)  

83  -> (PARTITION p1 VALUES less than (1),  

84  -> PARTITION p2 VALUES less than (5),  

85  -> PARTITION p3 VALUES less than MAXVALUE);  

86 Query OK, 15 rows affected (0.21 sec)   //对15数据进行分区  

87 Records: 15  Duplicates: 0  Warnings: 0  

88    

89 //总共有15条  

90 mysql> select count(*) from aa;  

91 +----------+  

92 | count(*) |  

93 +----------+  

94 |       15 |  

95 +----------+  

96 1 row in set (0.00 sec)  

97    

98 //删除一个分区  

99 mysql> alter table aa drop partition p2;  

100 Query OK, 0 rows affected (0.30 sec)  

101 Records: 0  Duplicates: 0  Warnings: 0  

102    

103 //只有11条了,说明对现有的表分区成功了  

104 mysql> select count(*) from aa;  

105 +----------+  

106 | count(*) |  

107 +----------+  

108 |       11 |  

109 +----------+  

110 1 row in set (0.00 sec)

3,list分区
LIST分区中每个分区的定义和选择是基于某列的值从属于一个值列表集中的一个值,而RANGE分 区是从属于一个连续区间值的集合。



view sourceprint?1 //这种方式失败  

2 mysql> CREATE TABLE IF NOT EXISTS `list_part` (  

3  ->   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',  

4  ->   `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',  

5  ->   `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',  

6  ->   `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0为男,1为女',  

7  ->   PRIMARY KEY (`id`)  

8  -> ) ENGINE=INNODB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1  

9  -> PARTITION BY LIST (province_id) (  

10  ->     PARTITION p0 VALUES IN (1,2,3,4,5,6,7,8),  

11  ->     PARTITION p1 VALUES IN (9,10,11,12,16,21),  

12  ->     PARTITION p2 VALUES IN (13,14,15,19),  

13  ->     PARTITION p3 VALUES IN (17,18,20,22,23,24)  

14  -> );  

15 ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

16    

17 //这种方式成功  

18 mysql> CREATE TABLE IF NOT EXISTS `list_part` (  

19  ->   `id` int(11) NOT NULL  COMMENT '用户ID',  

20  ->   `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',  

21  ->   `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',  

22  ->   `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0为男,1为女'

23  -> ) ENGINE=INNODB  DEFAULT CHARSET=utf8  

24  -> PARTITION BY LIST (province_id) (  

25  ->     PARTITION p0 VALUES IN (1,2,3,4,5,6,7,8),  

26  ->     PARTITION p1 VALUES IN (9,10,11,12,16,21),  

27  ->     PARTITION p2 VALUES IN (13,14,15,19),  

28  ->     PARTITION p3 VALUES IN (17,18,20,22,23,24)  

29  -> );  

30 Query OK, 0 rows affected (0.33 sec)



上面的这个创建list分区时,如果有主銉的话,分区时主键必须在其中,不然就会报错。如果我不用主键,分区就创建成功了,一般情况下,一个张表肯定会有一个主键,这算是一个分区的局限性吧。

如果对数据进行测试,请参考range分区的测试来操作

4,hash分区
HASH分区主要用来确保数据在预先确定数目的分区中平均分布,你所要做的只是基于将要被哈希的列值指定一个列值或表达式,以 及指定被分区的表将要被分割成的分区数量。

view sourceprint?1 mysql> CREATE TABLE IF NOT EXISTS `hash_part` (  

2  ->   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论ID',  

3  ->   `comment` varchar(1000) NOT NULL DEFAULT '' COMMENT '评论',  

4  ->   `ip` varchar(25) NOT NULL DEFAULT '' COMMENT '来源IP',  

5  ->   PRIMARY KEY (`id`)  

6  -> ) ENGINE=INNODB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1  

7  -> PARTITION BY HASH(id)  

8  -> PARTITIONS 3;  

9 Query OK, 0 rows affected (0.06 sec)

测试请参考range分区的操作

5,key分区
按照KEY进行分区类似于按照HASH分区,除了HASH分区使用的用 户定义的表达式,而KEY分区的 哈希函数是由MySQL 服务器提供。

view sourceprint?1 mysql> CREATE TABLE IF NOT EXISTS `key_part` (  

2  ->   `news_id` int(11) NOT NULL  COMMENT '新闻ID',  

3  ->   `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新闻内容',  

4  ->   `u_id` varchar(25) NOT NULL DEFAULT '' COMMENT '来源IP',  

5  ->   `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '时间'

6  -> ) ENGINE=INNODB  DEFAULT CHARSET=utf8  

7  -> PARTITION BY LINEAR HASH(YEAR(create_time))  

8  -> PARTITIONS 3;  

9 Query OK, 0 rows affected (0.07 sec)

测试请参考range分区的操作

6,子分区
子分区是分区表中每个分区的再次分割,子分区既可以使用HASH希分区,也可以使用KEY分区。这 也被称为复合分区(composite partitioning)。

1,如果一个分区中创建了子分区,其他分区也要有子分区

2,如果创建了了分区,每个分区中的子分区数必有相同

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

view sourceprint?1 mysql> CREATE TABLE IF NOT EXISTS `sub_part` (  

2  ->   `news_id` int(11) NOT NULL  COMMENT '新闻ID',  

3  ->   `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新闻内容',  

4  ->   `u_id`  int(11) NOT NULL DEFAULT 0s COMMENT '来源IP',  

5  ->   `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '时间'

6  -> ) ENGINE=INNODB  DEFAULT CHARSET=utf8  

7  -> PARTITION BY RANGE(YEAR(create_time))  

8  -> SUBPARTITION BY HASH(TO_DAYS(create_time))(  

9  -> PARTITION p0 VALUES LESS THAN (1990)(SUBPARTITION s0,SUBPARTITION s1,SUBPARTITION s2),  

10  -> PARTITION p1 VALUES LESS THAN (2000)(SUBPARTITION s3,SUBPARTITION s4,SUBPARTITION good),  

11  -> PARTITION p2 VALUES LESS THAN MAXVALUE(SUBPARTITION tank0,SUBPARTITION tank1,SUBPARTITION tank3)  

12  -> );  

13 Query OK, 0 rows affected (0.07 sec)

三,分区管理
1,删除分区

mysql> alter table user drop partition p4;  
2,新增分区

view sourceprint?1 //range添加新分区  

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

3 Query OK, 0 rows affected (0.06 sec)  

4 Records: 0  Duplicates: 0  Warnings: 0  

5    

6 //list添加新分区  

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

8 Query OK, 0 rows affected (0.01 sec)  

9 Records: 0  Duplicates: 0  Warnings: 0  

10    

11 //hash重新分区  

12 mysql> alter table hash_part add partition partitions 4;  

13 Query OK, 0 rows affected (0.12 sec)  

14 Records: 0  Duplicates: 0  Warnings: 0  

15    

16 //key重新分区  

17 mysql> alter table key_part add partition partitions 4;  

18 Query OK, 1 row affected (0.06 sec)    //有数据也会被重新分配  

19 Records: 1  Duplicates: 0  Warnings: 0  

20    

21 //子分区添加新分区,虽然我没有指定子分区,但是系统会给子分区命名的  

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

23 Query OK, 0 rows affected (0.02 sec)  

24 Records: 0  Duplicates: 0  Warnings: 0  

25    

26 mysql> show create table sub1_partG;  

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

28  Table: sub1_part  

29 Create Table: CREATE TABLE `sub1_part` (  

30  `news_id` int(11) NOT NULL COMMENT '新闻ID',  

31  `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新闻内容',  

32  `u_id` varchar(25) NOT NULL DEFAULT '' COMMENT '来源IP',  

33  `create_time` date NOT NULL DEFAULT '0000-00-00' COMMENT '时间'

34 ) ENGINE=InnoDB DEFAULT CHARSET=utf8  

35 !50100 PARTITION BY RANGE (YEAR(create_time))  

36 SUBPARTITION BY HASH (TO_DAYS(create_time))  

37 (PARTITION p0 VALUES LESS THAN (1990)  

38  (SUBPARTITION s0 ENGINE = InnoDB,  

39  SUBPARTITION s1 ENGINE = InnoDB,  

40  SUBPARTITION s2 ENGINE = InnoDB),  

41  PARTITION p1 VALUES LESS THAN (2000)  

42  (SUBPARTITION s3 ENGINE = InnoDB,  

43  SUBPARTITION s4 ENGINE = InnoDB,  

44  SUBPARTITION good ENGINE = InnoDB),  

45  PARTITION p2 VALUES LESS THAN (3000)  

46  (SUBPARTITION tank0 ENGINE = InnoDB,  

47  SUBPARTITION tank1 ENGINE = InnoDB,  

48  SUBPARTITION tank3 ENGINE = InnoDB),  

49  PARTITION p3 VALUES LESS THAN MAXVALUE  

50  (SUBPARTITION p3sp0 ENGINE = InnoDB,    //子分区的名子是自动生成的  

51  SUBPARTITION p3sp1 ENGINE = InnoDB,  

52  SUBPARTITION p3sp2 ENGINE = InnoDB))  

53 1 row in set (0.00 sec)


3,重新分区

view sourceprint?1 //range重新分区  

2 mysql> ALTER TABLE user REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES LESS THAN MAXVALUE);  

3 Query OK, 11 rows affected (0.08 sec)  

4 Records: 11  Duplicates: 0  Warnings: 0  

5    

6 //list重新分区  

7 mysql> ALTER TABLE list_part REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES in (1,2,3,4,5));  

8 Query OK, 0 rows affected (0.28 sec)  

9 Records: 0  Duplicates: 0  Warnings: 0  

10    

11 //hash和key分区不能用REORGANIZE,官方网站说的很清楚  

12 mysql> ALTER TABLE key_part REORGANIZE PARTITION COALESCE PARTITION 9;  

13 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,跨多个磁盘来分散数据查询,来获得更大的查询吞吐量

课外阅读
:http://dev.mysql.com/doc/refman/5.1/zh/partitioning.html

Tags: ,
一,先说一下为什么要分表
当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。

根据个人经验,mysql执行一个sql的过程如下:
1,接收到sql;

2,把sql放到排队队列中 ;

3,执行sql;

4,返回执行结果。

在这个执行过程中最花时间在什么地方呢?第一,是排队等待的时间,第二,sql的执行时间。其实这二个是一回事,等待的同时,肯定有sql在执行。所以我们要缩短sql的执行时间。

mysql中有一种机制是表锁定和行锁定,为什么要出现这种机制,是为了保证数据的完整性,我举个例子来说吧,如果有二个sql都要修改同一张表的同一条数据,这个时候怎么办呢,是不是二个sql都可以同时修改这条数据呢?很显然mysql对这种情况的处理是,一种是表锁定(myisam存储引擎),一个是行锁定(innodb存储引擎)。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作。如果数据太多,一次执行的时间太长,等待的时间就越长,这也是我们为什么要分表的原因。

二,分表
1,做mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等
有人会问mysql集群,根分表有什么关系吗?虽然它不是实际意义上的分表,但是它启到了分表的作用,做集群的意义是什么呢?为一个数据库减轻负担,说白了就是减少sql排队队列中的sql的数量,举个例子:有10个sql请求,如果放在一个数据库服务器的排队队列中,他要等很长时间,如果把这10个sql请求,分配到5个数据库服务器的排队队列中,一个数据库服务器的队列中只有2个,这样等待时间是不是大大的缩短了呢?这已经很明显了。所以我把它列到了分表的范围以内

优点:扩展性好,没有多个分表后的复杂操作(php代码)

缺点:单个表的数据量还是没有变,一次操作所花的时间还是那么多,硬件开销大。

2,预先估计会出现大数据量并且访问频繁的表,将其分为若干个表
这种预估大差不差的,论坛里面发表帖子的表,时间长了这张表肯定很大,几十万,几百万都有可能。 聊天室里面信息表,几十个人在一起一聊一个晚上,时间长了,这张表的数据肯定很大。像这样的情况很多。所以这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。以聊天信息表为例:

我事先建100个这样的表,message_00,message_01,message_02……….message_98,message_99.然后根据用户的ID来判断这个用户的聊天信息放到哪张表里面,你可以用hash的方式来获得,可以用求余的方式来获得,方法很多,各人想各人的吧。下面用hash的方法来获得表名:

view sourceprint?1
2 function get_hash_table($table,$userid) {  

3  $str = crc32($userid);  

4  if($str<0){  

5  $hash = "0".substr(abs($str), 0, 1);  

6  }else{  

7  $hash = substr($str, 0, 2);  

8  }  

9    

10  return $table."_".$hash;  

11 }  

12    

13 echo get_hash_table('message','user18991');     //结果为message_10  

14 echo get_hash_table('message','user34523');    //结果为message_13  

15 ?>

说明一下,上面的这个方法,告诉我们user18991这个用户的消息都记录在message_10这张表里,user34523这个用户的消息都记录在message_13这张表里,读取的时候,只要从各自的表中读取就行了。

优点:避免一张表出现几百万条数据,缩短了一条sql的执行时间

缺点:当一种规则确定时,打破这条规则会很麻烦,上面的例子中我用的hash算法是crc32,如果我现在不想用这个算法了,改用md5后,会使同一个用户的消息被存储到不同的表中,这样数据乱套了。扩展性很差。

—————PHP10086:根据userid,或者时间拆分,建立路由规则调度,确定聚合查询的时候麻烦。

3,利用merge存储引擎来实现分表
我觉得这种方法比较适合,那些没有事先考虑,而已经出现了得,数据查询慢的情况。这个时候如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码,因为程序里面的sql语句已经写好了,现在一张表要分成几十张表,甚至上百张表,这样sql语句是不是要重写呢?举个例子,我很喜欢举子

mysql>show engines;的时候你会发现mrg_myisam其实就是merge。

view sourceprint?1 mysql> CREATE TABLE IF NOT EXISTS `user1` (  

2  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  

3  ->   `name` varchar(50) DEFAULT NULL,  

4  ->   `sex` int(1) NOT NULL DEFAULT '0',  

5  ->   PRIMARY KEY (`id`)  

6  -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  

7 Query OK, 0 rows affected (0.05 sec)  

8    

9 mysql> CREATE TABLE IF NOT EXISTS `user2` (  

10  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  

11  ->   `name` varchar(50) DEFAULT NULL,  

12  ->   `sex` int(1) NOT NULL DEFAULT '0',  

13  ->   PRIMARY KEY (`id`)  

14  -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  

15 Query OK, 0 rows affected (0.01 sec)  

16    

17 mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('张映', 0);  

18 Query OK, 1 row affected (0.00 sec)  

19    

20 mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);  

21 Query OK, 1 row affected (0.00 sec)  

22    

23 mysql> CREATE TABLE IF NOT EXISTS `alluser` (  

24  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  

25  ->   `name` varchar(50) DEFAULT NULL,  

26  ->   `sex` int(1) NOT NULL DEFAULT '0',  

27  ->   INDEX(id)  

28  -> ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ;  

29 Query OK, 0 rows affected, 1 warning (0.00 sec)  

30    

31 mysql> select id,name,sex from alluser;  

32 +----+--------+-----+  

33 | id | name   | sex |  

34 +----+--------+-----+  

35 |  1 | 张映 |   0 |  

36 |  1 | tank   |   1 |  

37 +----+--------+-----+  

38 2 rows in set (0.00 sec)  

39    

40 mysql> INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0);  

41 Query OK, 1 row affected (0.00 sec)  

42    

43 mysql> select id,name,sex from user2  

44  -> ;  

45 +----+-------+-----+  

46 | id | name  | sex |  

47 +----+-------+-----+  

48 |  1 | tank  |   1 |  

49 |  2 | tank2 |   0 |  

50 +----+-------+-----+  

51 2 rows in set (0.00 sec)

从上面的操作中,我不知道你有没有发现点什么?假如我有一张用户表user,有50W条数据,现在要拆成二张表user1和user2,每张表25W条数据,

INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id <= 250000

INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id > 250000

这样我就成功的将一张user表,分成了二个表,这个时候有一个问题,代码中的sql语句怎么办,以前是一张表,现在变成二张表了,代码改动很大,这样给程序员带来了很大的工作量,有没有好的办法解决这一点呢?办法是把以前的user表备份一下,然后删除掉,上面的操作中我建立了一个alluser表,只把这个alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的

a,如果你使用 alter table 来把 merge 表变为其它表类型,到底层表的映射就被丢失了。取而代之的,来自底层 myisam 表的行被复制到已更换的表中,该表随后被指定新类型。

b,网上看到一些说replace不起作用,我试了一下可以起作用的。晕一个先

view sourceprint?1 mysql> UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2;    

2    

3 Query OK, 1 row affected (0.00 sec)    

4    

5 Rows matched: 1  Changed: 1  Warnings: 0    

6    

7    

8    

9 mysql> select * from alluser;    

10    

11 +----+--------+-----+    

12    

13 | id | name   | sex |    

14    

15 +----+--------+-----+    

16    

17 |  1 | 张映 |   0 |    

18    

19 |  1 | tank   |   1 |    

20    

21 |  2 | tank2  |   1 |    

22    

23 +----+--------+-----+    

24    

25 3 rows in set (0.00 sec)

c,一个 merge 表不能在整个表上维持 unique 约束。当你执行一个 insert,数据进入第一个或者最后一个 myisam 表(取决于 insert_method 选项的值)。mysql 确保唯一键值在那个 myisam 表里保持唯一,但不是跨集合里所有的表。

d,当你创建一个 merge 表之时,没有检查去确保底层表的存在以及有相同的机构。当 merge 表被使用之时,mysql 检查每个被映射的表的记录长度是否相等,但这并不十分可靠。如果你从不相似的 myisam 表创建一个 merge 表,你非常有可能撞见奇怪的问题。

好困睡觉了,c和d在网上看到的,没有测试,大家试一下吧。

优点:扩展性好,并且程序代码改动的不是很大

缺点:这种方法的效果比第二种要差一点

三,总结一下

上面提到的三种方法,我实际做过二种,第一种和第二种。第三种没有做过,所以说的细一点。哈哈。做什么事都有一个度,超过个度就过变得很差,不能一味的做数据库服务器集群,硬件是要花钱买的,也不要一味的分表,分出来1000表,mysql的存储归根到底还以文件的形势存在硬盘上面,一张表对应三个文件,1000个分表就是对应3000个文件,这样检索起来也会变的很慢。我的建议是

方法1和方法2结合的方式来进行分表

方法1和方法3结合的方式来进行分表

我的二个建议适合不同的情况,根据个人情况而定,我觉得会有很多人选择方法1和方法3结合的方式

—–PHP10086手记:
关于merge 表分表:
聚合表alluser 要指定DEFAULT CHARSET=utf8,统一编码不然报错。
子表需要是MyISAM引擎,仅仅适合与myisam引擎的表
每个子表的结构必须一致,主表和子表的结构需要一致
每个子表的索引在merge表中都会存在,所以在merge表中不能根据该索引进行唯一性检索
REPLACE在merge表中不会工作
AUTO_INCREMENT 不会按照你所期望的方式工作-
创建Mysql Merge表的参数 INSERT_METHOD有几个参数 :

LAST  如果你执行insert 指令来操作merge表时,插入操作会把数据添加到最后一个子表中。

FIRST  同理,执行插入数据时会把数据添加到第一个子表中。

关于merge删除
如果删除mrg表,那么各个子表间将不会有联系。但是如果删除其中的任一子表,对于GNU/LINUX来说,merge表结构及数据仍然存在。

Tags: ,

DataTables(http://www.datatables.net/)是我功能强大的表格解决方案。

先把它主页上写的特性翻译罗列如下:
可变长度分页;动态过滤;多列排序,带数据类型检测功能;列宽度的智能处理;从多种数据源获取数据(DOM,js Array, ajax file, server-side returning);滚动配置属性;完整国际化支持; jquery UI ThemeRoller支持;经历了个2600多个单元测试,相当牢固;有为数不少的插件支持;免费的;状态保存能力;支持隐藏列;动态创建表格的能力;自动ajax数据加载;自定义DOM位置;单列过滤(这个与前面的过滤有区别么?);多种分页器;无损的DOM交互;参与排序的列高亮;高级数据源配置;扩展的插件支持功能;可以用css完全配置表象;丰富的文档; 110多个例子;对Adobe AIR的完全支持。

引入

使用

Javascript代码  
$(document).ready(function(){      $('#example').dataTable();  });    // 另一个例子  $(document).ready(function(){      $('#example').dataTable({          "bInfo": false      });  });  


要注意的是,要被dataTable处理的table对象,必须有thead与tbody,而且,结构要规整(数据不一定要完整),这样才能正确处理。

以下是在进行dataTable绑定处理时候可以附加的参数:
属性名称取值范围解释
bAutoWidthtrue or false, default true是否自动计算表格各列宽度
bDeferRendertrue or false, default false用于渲染的一个参数
bFiltertrue or false, default true开关,是否启用客户端过滤功能
bInfotrue or false, default true开关,是否显示表格的一些信息
bJQueryUItrue or false, default false是否使用jquery ui themeroller的风格
bLengthChangetrue or false, default true开关,是否显示一个每页长度的选择条(需要分页器支持)
bPaginatetrue or false, default true开关,是否显示(使用)分页器
bProcessingtrue or false, defualt false开关,以指定当正在处理数据的时候,是否显示“正在处理”这个提示信息
bScrollInfinitetrue or false, default false开关,以指定是否无限滚动(与sScrollY配合使用),在大数据量的时候很有用。当这个标志为true的时候,分页器就默认关闭
bSorttrue or false, default true开关,是否让各列具有按列排序功能
bSortClassestrue or false, default true开关,指定当当前列在排序时,是否增加classes 'sorting_1', 'sorting_2' and 'sorting_3',打开后,在处理大数据时,性能有所损失
bStateSavetrue or false, default false开关,是否打开客户端状态记录功能。这个数据是记录在cookies中的,打开了这个记录后,即使刷新一次页面,或重新打开浏览器,之前的状态都是保存下来的
sScrollX'disabled' or  '100%' 类似的字符串是否开启水平滚动,以及指定滚动区域大小
sScrollY'disabled' or '200px' 类似的字符串是否开启垂直滚动,以及指定滚动区域大小
------
选项
aaSortingarray array[int,string], 如[], [[0,'asc'], [0,'desc']]指定按多列数据排序的依据
aaSortingFixed同上同上。唯一不同点是不能被用户的自定义配置冲突
aLengthMenudefault [10, 25, 50, 100],可以为一维数组,也可为二维数组,比如:[[10, 25, 50, -1], [10, 25, 50, "All"]]这个为选择每页的条目数,当使用一个二维数组时,二维层面只能有两个元素,第一个为显示每页条目数的选项,第二个是关于这些选项的解释
aoSearchColsdefault null, 类似:[null, {"sSearch": "My filter"}, null,{"sSearch": "^[0-9]", "bEscapeRegex": false}]给每个列单独定义其初始化搜索列表特性(这一块还没搞懂)
asStripClassesdefault ['odd', 'even'], 比如['strip1', 'strip2', 'strip3']指定要被应用到各行的class风格,会自动循环
bDestroytrue or false, default false用于当要在同一个元素上执行新的dataTable绑定时,将之前的那个数据对象清除掉,换以新的对象设置
bRetrievetrue or false, default false用于指明当执行dataTable绑定时,是否返回DataTable对象
bScrollCollapsetrue or false, default false指定适当的时候缩起滚动视图
bSortCellsToptrue or false, default false(未知的东东)
iCookieDuration整数,默认7200,单位为秒指定用于存储客户端信息到cookie中的时间长度,超过这个时间后,自动过期
iDeferLoading整数,默认为null延迟加载,它的参数为要加载条目的数目,通常与bServerSide,sAjaxSource等配合使用
iDisplayLength整数,默认为10用于指定一屏显示的条数,需开启分页器
iDisplayStart整数,默认为0用于指定从哪一条数据开始显示到表格中去
iScrollLoadGap整数,默认为100用于指定当DataTable设置为滚动时,最多可以一屏显示多少条数据
oSearch默认{ "sSearch": "", "bRegex": false, "bSmart": true }又是初始时指定搜索参数相关的,有点复杂,没搞懂目前
sAjaxDataProp字符串,default 'aaData'指定当从服务端获取表格数据时,数据项使用的名字
sAjaxSourceURL字符串,default null指定要从哪个URL获取数据
sCookiePrefix字符串,default 'SpryMedia_DataTables_'当打开状态存储特性后,用于指定存储在cookies中的字符串的前缀名字
sDomdefault lfrtip (when bJQueryUI is false) or <"H"lfr>t<"F"ip> (when bJQueryUI is true)这是用于定义DataTable布局的一个强大的属性,另开专门文档来补充说明吧
sPaginationType'full_numbers' or 'two_button', default 'two_button'用于指定分页器风格
sScrollXInnerstring default 'disabled'又是水平滚动相关的,没搞懂啥意思


DataTable支持如下回调函数
回调函数名称参数返回值默认功能
fnCookieCallback1.string: Name of the cookie defined by DataTables 2.object: Data to be stored in the cookie 3.string: Cookie expires string 4.string: Path of the cookie to setstring: cookie formatted string (which should be encoded by using encodeURIComponent())null当每次cookies改变时,会触发这个函数调用
fnDrawCallback在每次table被draw完后调用,至于做什么就看着办吧
fnFooterCallback1.node : "TR" element for the footer 2.array array strings : Full table data (as derived from the original HTML) 3.int : Index for the current display starting point in the display array< 4.int : Index for the current display ending point in the display array 5.array int : Index array to translate the visual position to the full data array用于在每次重画的时候修改表格的脚部
fnFormatNumber1.int : number to be formattedString : formatted string for DataTables to show the number有默认的用于在大数字上,自动加入一些逗号,分隔开
fnHeaderCallback1.node : "TR" element for the header 2.array array strings : Full table data (as derived from the original HTML) 3.int : Index for the current display starting point in the display array 4.int : Index for the current display ending point in the display array 5.array int : Index array to translate the visual position to the full data array用于在每次draw发生时,修改table的header
fnInfoCallback1.object: DataTables settings object 2.int: Starting position in data for the draw 3.int: End position in data for the draw 4.int: Total number of rows in the table (regardless of filtering) 5.int: Total number of rows in the data set, after filtering 6.string: The string that DataTables has formatted using it's own rulesstring: The string to be displayed in the information element.用于传达table信息
fnInitComplete1.object:oSettings - DataTables settings object表格初始化完成后调用
fnPreDrawCallback1.object:oSettings - DataTables settings objectBoolean用于在开始绘制之前调用,返回false的话,会阻止draw事件发生;返回其它值,draw可以顺利执行
fnRowCallback1.node : "TR" element for the current row 2.array strings : Raw data array for this row (as derived from the original HTML) 3.int : The display index for the current table draw 4.int : The index of the data in the full list of rows (after filtering)node : "TR" element for the current row当创建了行,但还未绘制到屏幕上的时候调用,通常用于改变行的class风格
fnServerData1.string: HTTP source to obtain the data from (i.e. sAjaxSource) 2.array objects: A key/value pair object containing the data to send to the server 3.function: Function to be called on completion of the data get process that will draw the data on the page.void$.getJSON用于替换默认发到服务端的请求操作
fnStateLoadCallback1.object:oSettings - DataTables settings object 2.object:oData - Object containing information retrieved from the state saving cookie which should be restored. For the exact properties please refer to the DataTables code.Boolean - false if the state should not be loaded, true otherwise在cookies中的数据被加载前执行,可以方便地修改这些数据
fnStateSaveCallback1.object:oSettings - DataTables settings object 2.String:sValue - a JSON string (without the final closing brace) which should be stored in the state saving cookie.String - the full string that should be used to save the state在状态数据被存储到cookies前执行,可以方便地做一些预操作

Tags: ,
分页: 4/127 第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]