为何要分表和分区?html
平常开发中咱们常常会遇到大表的状况,所谓的大表是指存储了百万级乃至千万级条记录的表。这样的表过于庞大,致使数据库在查询和插入的时候耗时太长,性能低下,若是涉及联合查询的状况,性能会更加糟糕。分表和表分区的目的就是减小数据库的负担,提升数据库的效率,一般点来说就是提升表的增删改查效率。java
什么是分表?mysql
分表是将一个大表按照必定的规则分解成多张具备独立存储空间的实体表,咱们能够称为子表,每一个表都对应三个文件,MYD数据文件,.MYI索引文件,.frm表结构文件。这些子表能够分布在同一块磁盘上,也能够在不一样的机器上。app读写的时候根据事先定义好的规则获得对应的子表名,而后去操做它。sql
什么是分区?数据库
分区和分表类似,都是按照规则分解表。不一样在于分表将大表分解为若干个独立的实体表,而分区是将数据分段划分在多个位置存放,能够是同一块磁盘也能够在不一样的机器。分区后,表面上仍是一张表,但数据散列到多个位置了。app读写的时候操做的仍是大表名字,db自动去组织分区的数据。并发
mysql分表和分区有什么联系呢?
1.都能提升mysql的性高,在高并发状态下都有一个良好的表现。
2.分表和分区不矛盾,能够相互配合的,对于那些大访问量,而且表数据比较多的表,咱们能够采起分表和分区结合的方式(若是merge这种分表方式,不能和分区配合的话,能够用其余的分表试),访问量不大,可是表数据不少的表,咱们能够采起分区的方式等。
3.分表技术是比较麻烦的,须要手动去建立子表,app服务端读写时候须要计算子表名。采用merge好一些,但也要建立子表和配置子表间的union关系。
4.表分区相对于分表,操做方便,不须要建立子表。app
分表的几种方式:less
一、mysql集群高并发
它并非分表,但起到了和分表相同的做用。集群可分担数据库的操做次数,将任务分担到多台数据库上。集群能够读写分离,减小读写压力。从而提高数据库性能。性能
二、自定义规则分表
大表能够按照业务的规则来分解为多个子表。一般为如下几种类型,也可本身定义规则。
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;
}
|
三、利用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
)
);
|