您的位置:首页 > 数据库 > MySQL

Mysql分区分表的定义和区别以及实际使用

2017-07-04 17:23 281 查看
为什么需要分区分表?

数据库查询本质上是一种在硬盘上进行的i/o文件操作。数据记录过大造成i/o性能大幅度下降,导致查询效率大大降低。为避免i/o性能大幅度下降,需采用分区和分表的方式,通过分摊的形式来降低i/o性能下降。

什么是分表?

分表,顾名思义,其是将一个表的数据划分到多个独立的表中,相当于对数据进行人为的划分,分表中我们先找到数据所对应的子表,再在子表进行数据查询,无疑这种方式比在一个大表中进行数据查询要快的多。它将大表耗时的i/o操作,分摊子表中。

什么是分区?

分区是将数据分段划分在多个位置存储,可以是同一块磁盘也可以是不同的机器。分区后,表面上还是一张表,但数据散列到了多个位置中了。在进行数据查询的时候操作的还是大表的名字,db自动去组织分区的数据

 

 

Mysql分区分表的区别:

1,实现方式上 

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

   
Sql代码  

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到底是什么东西 

 
Sql代码  

1.     [root@BlackGhost test]# cat alluser.MRG |more    
2.       user1    
3.       user2    
4.       #INSERT_METHOD=LAST  

  

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

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

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)分区呢,不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表呢,还是一张表。数据
11f4a
处理还是由自己来完成。 

3、提高性能上 

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

b)mysql提出了分区的概念,我觉得就想突破磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。 
在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。 

4、实现的难易度上 

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

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

 

mysql分表和分区有什么联系呢?
1.都能提高mysql的性高,在高并发状态下都有一个良好的表现。
2.分表和分区不矛盾,可以相互配合的,对于那些大访问量,并且表数据比较多的表,我们可以采取分表和分区结合的方式(如果merge这种分表方式,不能和分区配合的话,可以用其他的分表试),访问量不大,但是表数据很多的表,我们可以采取分区的方式等。
3.分表技术是比较麻烦的,需要手动去创建子表,app服务端读写时候需要计算子表名。采用merge好一些,但也要创建子表和配置子表间的union关系。
4.表分区相对于分表,操作方便,不需要创建子表。
 

 

分表的几种方式:

1、mysql集群

它并不是分表,但起到了和分表相同的作用。集群可分担数据库的操作次数,将任务分担到多台数据库上。集群可以读写分离,减少读写压力。从而提升数据库性能。

2、自定义规则分表

大表可以按照业务的规则来分解为多个子表。通常为以下几种类型,也可自己定义规        

1

2

3

4

5

Range(范围)–这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区。

Hash(哈希)–这中模式允许通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。

Key(键值)-上面Hash模式的一种延伸,这里的Hash Key是MySQL系统产生的。

List(预定义列表)–这种模式允许系统通过预定义的列表的值来对数据进行分割。

Composite(复合模式)–以上模式的组合使用 

分表规则与分区规则一样,在分区模块详细介绍。

下面以Range简单介绍下如何分表(按照年份表)。

假设表结构有4个字段:自增id,姓名,存款金额,存款日期

把存款日期作为规则分表,分别创建几个表

2011年:account_2011

2012年:account_2012

……

2015年:account_2015

app在读写的时候根据日期来查找对应的表名,需要手动来判定。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

var getTableName = function() {

    var data = {

        name: 'tom',

        money: 2800.00,

        date: '201410013059'

    };

    var tablename = 'account_';

    var year = parseInt(data.date.substring(0, 4));

    if (year < 2012) {

        tablename += 2011; // account_2011

    } else if (year < 2013) {

        tablename += 2012; // account_2012

    } else if (year < 2014) {

        tablename += 2013; // account_2013

    } else if (year < 2015) {

        tablename += 2014; // account_2014

    } else {

        tablename += 2015; // account_2015

    }

    return tablename;

}

3、利用merge存储引擎来实现分表

merge分表,分为主表和子表,主表类似于一个壳子,逻辑上封装了子表,实际上数据都是存储在子表中的。

我们可以通过主表插入和查询数据,如果清楚分表规律,也可以直接操作子表。

子表2011年

1

2

3

4

5

6

7

8

9

10

11

12

13

14

CREATE TABLE `account_2011` (

`id`  int(11) NOT NULL AUTO_INCREMENT ,

`name`  varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,

`money`  float NOT NULL ,

`tradeDate`  datetime NOT NULL

PRIMARY KEY (`id`)

)

ENGINE=MyISAM

DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci

AUTO_INCREMENT=2

CHECKSUM=0

ROW_FORMAT=DYNAMIC

DELAY_KEY_WRITE=0

;

子表2012年

1

2

3

4

5

6

7

8

9

10

11

12

13

14

CREATE TABLE `account_2012` (

`id`  int(11) NOT NULL AUTO_INCREMENT ,

`name`  varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,

`money`  float NOT NULL ,

`tradeDate`  datetime NOT NULL

PRIMARY KEY (`id`)

)

ENGINE=MyISAM

DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci

AUTO_INCREMENT=2

CHECKSUM=0

ROW_FORMAT=DYNAMIC

DELAY_KEY_WRITE=0

;

主表,所有年

1

2

3

4

5

6

7

8

9

10

11

12

13

CREATE TABLE `account_all` (

`id`  int(11) NOT NULL AUTO_INCREMENT ,

`name`  varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,

`money`  float NOT NULL ,

`tradeDate`  datetime NOT NULL

PRIMARY KEY (`id`)

)

ENGINE=MRG_MYISAM

DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci

UNION=(`account_2011`,`account_2012`)

INSERT_METHOD=LAST

ROW_FORMAT=DYNAMIC

;

创建主表的时候有个INSERT_METHOD,指明插入方式,取值可以是:0不允许插入;FIRST
插入到UNION中的第一个表; LAST插入到UNION中的最后一个表。

通过主表查询的时候,相当于将所有子表合在一起查询。这样并不能体现分表的优势,建议还是查询子表。

分区的几种方式

Range:

1

2

3

4

5

6

7

8

9

10

create table range(

  id int(11),

  money int(11) unsigned not null,

  date datetime

  )partition by range(year(date))(

  partition p2007 values less than (2008),

  partition p2008 values less than (2009),

  partition p2009 values less than (2010)

  partition p2010 values less than maxvalue

);

List:

1

2

3

4

5

6

7

create table list(

  a int(11),

  b int(11)

  )(partition by list (b)

  partition p0 values in (1,3,5,7,9),

  partition p1 values in (2,4,6,8,0)

 );

Hash:

1

2

3

4

5

create table hash(

  a int(11),

  b datetime

  )partition by hash (YEAR(b)

  partitions 4;

Key:

1

2

3

4

5

create table t_key(

  a int(11),

  b datetime)

  partition by key (b)

  partitions 4;

分区管理

新增分区

1

2

ALTER TABLE sale_data

ADD PARTITION (PARTITION p201010 VALUES LESS THAN (201011));

删除分区
--当删除了一个分区,也同时删除了该分区中所有的数据。
ALTER TABLE sale_data DROP PARTITION p201010;
分区的合并

下面的SQL,将p201001 - p201009合并为3个分区p2010Q1 - p2010Q3

1

2

3

4

5

6

7

8

9

ALTER TABLE sale_data

REORGANIZE PARTITION p201001,p201002,p201003,

p201004,p201005,p201006,

p201007,p201008,p201009 INTO

(

PARTITION p2010Q1 VALUES LESS THAN (201004),

PARTITION p2010Q2 VALUES LESS THAN (201007),

PARTITION p2010Q3 VALUES LESS THAN (201010)

);

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐