mysql分表和表分区详解

为什么要分表和分区?

今天在公司听到一个dba团队大牛的分享,将大数据集情况下如何处理,如何快速扩容,如何用有限资源进行最大化利用数据库,解约成本。其中讲到分表,分区等概念,不是很懂,所以查了一些博客,以下这篇感觉不错,mark一下。

原文链接:http://www.2cto.com/database/201503/380348.html

日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表。这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果设计联合查询的情况,性能会更加糟糕。分表和表分区的目的是减小数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率。

什么是分表?

分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,每个表都对应三个文件,.MYD数据文件,.MYI索引文件,.frm表结构文件。这些子表可以分布在同一个磁盘上,也可以在不同的机器上。app读写的时候根据事先定义好的规则得到对应的子表名,然后去操作它。

什么是分区?

分区和分表相似,都是按照规则分解表。不同在于分表将大表分解为若干个独立的实体表,而分区是将数据分段划分在多个位置存放,可以是同一块磁盘也可以是不同的机器。分区后,表面上还是一张表,但数据散列到多个位置了。app读写的时候操作的还是大表名字,db自动去组织分区的数据。

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

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

2.自定义规则分表

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

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在读写的时候根据日期来查找对应的表名,需要手动来判断。

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年

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
;

主表:所有年

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中的最后一个表。

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

分区的几种方式
1.RANGE
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 
);
2.List
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) 
 );
3.Hash
create table hash( 
  a int(11), 
  b datetime 
  )partition by hash (YEAR(b) 
  partitions 4;
4.Key
create table t_key( 
  a int(11), 
  b datetime) 
  partition by key (b) 
  partitions 4;

新增分区

ALTER TABLE sale_data
ADD PARTITION (PARTITION p201010 VALUES LESS THAN (201011));

删除分区

ALTER TABLE sale_data DROP PARTITION p201010;

分区的合并

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)
);
一些数据库使用上的策略

这是最近一段时间内学到的经验,包括用到的或者听到的。

  1. 主从复制

    写主度从。Mysql有复制功能,多个数据库,包括主库和从库,一般读请求的数目要比写请求大的多,因此将读与写分开来可以有效提高数据库性能,现在主从已经可以达到几百毫秒内的一致。

  2. 异地灾备

    一般都需要有备份数据库,而且备份数据库要和业务数据库地理上隔离开,以防机房故障,如网络故障,硬件故障等。

  3. 重试策略

    一个读操作或者写操作失败,重试策略很重要,因为网络抖动不可避免,所以重试有效的方式是到不同的库去试。

  4. 一些dba需要懂的策略。

    扩容加表怎样将损失降到最低?先复制表,然后配上路由策略,将不属于这个分表的数据删除,在这个过程中,可读不可写;数据库加流控,流量到达一定程度,拒绝连接,可以防止数据库被压垮。

  5. 做符合当前数据量的事情

    大公司一般是这样的,你的产品线需要多少资源,给你分配多少资源,怎样让资源得到最大化利用,而不是一个产品线利益最大化。适合自己的才是最好的,代码策略,数据库策略都是这样的。不能看一个工具、产品技术有多厉害,可能它厉害的地方,你根本不需要呢。

posted @ 2016-11-03 22:36  白羊沈歌  阅读(351)  评论(0编辑  收藏  举报