MySQL--7--数据库分表分区--1
目录
为什么要分表和分区?
我们的数据库数据越来越大,随之而来的是单个表中数据太多。以至于查询速度变慢,而且由于表的锁机制导致应用操作也搜到严重影响,出现了数据库性能瓶颈。
mysql
中有一种机制是表锁定和行锁定,是为了保证数据的完整性。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql
必须等我对这条数据操作完了,才能对这条数据进行操作。当出现这种情况时,我们可以考虑分表或分区。
I.分表
i.什么是分表
分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,每个表都对应三个文件,MYD
数据文件,.MYI
索引文件,.frm
表结构文件。这些表可以分布在同一块磁盘上,也可以在不同的机器上。app
读写的时候根据事先定义好的规则得到对应的表名,然后去操作它。
app这个家角度思考的和学习的少。因为mysql是为了某种服务而存在,那么某种应用在访问mysql的时候,其代码是在开放的时候写入到了某个APP当中。当你在开发之后,再进行分表,但是app依旧是沿袭原来的代码进行访问mysql查询数据。这个时候就要注意你的分表规则。如果两者不一致,那么就会出现查询不到,或者其他的问题。
当使用merge分表的时候,更改的代码比较少。
将单个数据库表进行拆分,拆分成多个数据表,然后用户访问的时候,根据一定的算法(如用hash
的方式,也可以用求余(取模)的方式),让用户访问不同的表,这样数据分散到多个数据表中,减少了单个数据表的访问压力。提升了数据库访问性能。分表的目的就在于此,减小数据库的负担,缩短查询时间。
Mysql
分表分为
- 垂直切分
- 水平切分
垂直切分
是指数据表列的拆分,把一张列比较多的表拆分为多张表
通常我们按以下原则进行垂直拆分:
- 把不常用的字段单独放在一张表;
- 把
text
,blob
(binary large object
,二进制大对象)等大字段拆分出来放在附表中; - 经常组合查询的列放在一张表中;
垂直拆分更多时候就应该在数据表设计之初就执行的步骤,然后查询的时候用jion
关键起来即可。
水平拆分
是指数据表行的拆分,把一张的表的数据拆成多张表来存放。
水平拆分原则
通常情况下,我们使用hash
、取模等方式来进行表的拆分
比如一张有400W
的用户表users
,为提高其查询效率我们把其分成4张表users1
,users2
,users3
,users4
- 通过用`ID`取模的方法把数据分散到四张表内`Id%4= [0,1,2,3]`
- 然后查询,更新,删除也是通过取模的方法来查询
- 部分业务逻辑也可以通过地区,年份等字段来进行归档拆分;
进行拆分后的表,这时我们就要约束用户查询行为。比如我们是按年来进行拆分的,这个时候在页面设计上就约束用户必须要先选择年,然后才能进行查询。
问题:
- 拆分后,被拆分的表还存在吗?
- 能同时按不同方式拆分同一个表吗?
水平拆分之后,可以把表存储在不同的硬盘中,甚至可以存放在不同的服务器中。问题:如何实现呢? 注意的是,水平拆分之后,表的结构是没有更改,保持原来的结构。
ii.分表的几种方式
1.mysql
集群
它并不是分表,但起到了和分表相同的作用。集群可分担数据库的操作次数,将任务分担到多台数据库上。集群可以读写分离,减少读写压力。从而提升数据库性能。
2.预先估计会出现大数据量并且访问频繁的表,将其分为若干个表
适用范围:在设计之初,并且能估计出来。
根据一定的算法(如用hash
的方式,也可以用求余(取模)
的方式)让用户访问不同的表。
例如论坛里面发表帖子的表,时间长了这张表肯定很大,几十万,几百万都有可能。 聊天室里面信息表,几十个人在一起一聊一个晚上,时间长了,这张表的数据肯定很大。像这样的情况很多。所以这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。
以聊天信息表为例:我们事先建100
个这样的表,message_00,message_01,message_02..........message_98,message_99
.
方式一
然后根据用户的ID
来判断这个用户的聊天信息放到哪张表里面,可以用hash
的方式来获得,也可以用求余的方式来获得,方法很多。
不过这种方式,可能带来的结果是,有的表数据多,有的表数据少。
方式二
或者可以设计每张表容纳的数据量是N条,那么如何判断某张表的数据是否容量已满呢?可以在程序段对于要新增数据的表,在插入前先做统计表记录数量的操作,当<N条数据,就直接插入,当已经到达阀值,可以在程序段新创建数据库表(或者已经事先创建好),再执行插入操作)。
通过这种方式,可以保证每个表的数据量平均。
3.利用merge
存储引擎来实现分表
适用范围:已经有大量数据的表
注意:merge
存储引擎只能用于myisam
存储引擎,不适用于innodb
如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码,因为程序里面的sql语句已经写好了,用merge
存储引擎来实现分表, 这种方法比较适合。
merge
分表,分为主表和子表,主表类似于一个壳子,逻辑上封装了子表,实际上数据都是存储在子表中的。
我们可以通过主表插入和查询数据,如果清楚分表规律,也可以直接操作子表。
- 使用
merge
基本上不用改代码 - 此处理解:可以类比LVS,主表≈调度器(director),子表(real server)。
下面我们来实现一个简单的利用merge存储引擎来实现分表的演示:
创建一个完整表存储着所有的成员信息(表名为member
)
mysql> drop database IF EXISTS test;
mysql> use test;
create table member(
id bigint auto_increment primary key,
name varchar(20),
sex tinyint not null default '0'
)engine=myisam default charset=utf8 auto_increment=1;
加入点数据:
mysql> insert into member(name,sex) values('tom1',1);
mysql> insert into member(name,sex) select name,sex from member;
第二条语句多执行几次就有了很多数据
mysql> select * from member;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 1 | tom1 | 1 |
| 2 | tom1 | 1 |
| 3 | tom1 | 1 |
| 4 | tom1 | 1 |
| 5 | tom1 | 1 |
| 6 | tom1 | 1 |
| 7 | tom1 | 1 |
| 8 | tom1 | 1 |
| 9 | tom1 | 1 |
| 10 | tom1 | 1 |
| 11 | tom1 | 1 |
| 12 | tom1 | 1 |
| 13 | tom1 | 1 |
| 14 | tom1 | 1 |
| 15 | tom1 | 1 |
| 16 | tom1 | 1 |
+----+------+-----+
下面我们进行分表,这里我们把member
分两个表tb_member1
,tb_member2
mysql> use test;
DROP table IF EXISTS tb_member1;
create table tb_member1(
id bigint primary key ,
name varchar(20),
sex tinyint not null default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
DROP table IF EXISTS tb_member2;
create table tb_member2(
id bigint primary key,
name varchar(20),
sex tinyint not null default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
//创建tb_member2也可以用下面的语句 create table tb_member2 like tb_member1;
创建主表tb_member
DROP table IF EXISTS tb_member;
create table tb_member(
id bigint primary key ,
name varchar(20),
sex tinyint not null default '0'
) ENGINE=MERGE UNION=(tb_member1,tb_member2) INSERT_METHOD=LAST CHARSET=utf8 ;
注:INSERT_METHOD
,此参数
INSERT_METHOD = NO
表示该表不能做任何写入操作只作为查询使用INSERT_METHOD = LAST
表示插入到最后的一张表里面INSERT_METHOD = first
表示插入到第一张表里面
查看一下tb_member
表的结构:
mysql> desc tb_member;
mysql> desc tb_member;
+-------+-------------+------+-----+---------+-----------------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-----------------------------------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | tinyint(4) | NO | | 0 | |
+-------+-------------+------+-----+---------+------------------------------------------+
3 rows in set (0.00 sec)
注:查看子表与主表的字段定义要一致 接下来,我们把数据分到两个分表中去:
mysql> insert into tb_member1(id,name,sex) select id,name,sex from member where id%2=0;
mysql> insert into tb_member2(id,name,sex) select id,name,sex from member where id%2=1;
查看两个子表的数据:
mysql> select * from tb_member1;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 16 | tom1 | 1 |
| 14 | tom1 | 1 |
| 12 | tom1 | 1 |
| 10 | tom1 | 1 |
| 8 | tom1 | 1 |
| 6 | tom1 | 1 |
| 4 | tom1 | 1 |
| 2 | tom1 | 1 |
+----+------+-----+
8 rows in set (0.00 sec)
mysql> select * from tb_member2;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 3 | tom1 | 1 |
| 1 | tom1 | 1 |
| 5 | tom1 | 1 |
| 7 | tom1 | 1 |
| 9 | tom1 | 1 |
| 11 | tom1 | 1 |
| 13 | tom1 | 1 |
| 15 | tom1 | 1 |
+----+------+-----+
8 rows in set (0.00 sec)
查看一下主表的数据:
mysql> select * from tb_member;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 16 | tom1 | 1 |
| 14 | tom1 | 1 |
| 12 | tom1 | 1 |
| 10 | tom1 | 1 |
| 8 | tom1 | 1 |
| 6 | tom1 | 1 |
| 4 | tom1 | 1 |
| 2 | tom1 | 1 |
| 15 | tom1 | 1 |
| 13 | tom1 | 1 |
| 11 | tom1 | 1 |
| 9 | tom1 | 1 |
| 7 | tom1 | 1 |
| 5 | tom1 | 1 |
| 3 | tom1 | 1 |
| 1 | tom1 | 1 |
+----+------+-----+
16 rows in set (0.00 sec)
mysql> select * from tb_member where id=3;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 3 | tom1 | 1 |
+----+------+-----+
1 row in set (0.00 sec)
注意:总表只是一个外壳,存取数据发生在一个一个的子表里面。 注意:每个子表都有自已独立的相关表文件,而主表只是一个壳,并没有完整的相关表文件
[root@localhost ~]# ls -l /usr/local/mysql/data/test/tb_member*
-rw-r-----. 1 mysql mysql 8614 Sep 15 21:49 /usr/local/mysql/data/test/tb_member1.frm
-rw-r-----. 1 mysql mysql 320 Sep 16 00:02 /usr/local/mysql/data/test/tb_member1.MYD
-rw-r-----. 1 mysql mysql 2048 Sep 16 00:43 /usr/local/mysql/data/test/tb_member1.MYI
-rw-r-----. 1 mysql mysql 8614 Sep 15 21:50 /usr/local/mysql/data/test/tb_member2.frm
-rw-r-----. 1 mysql mysql 180 Sep 16 00:02 /usr/local/mysql/data/test/tb_member2.MYD
-rw-r-----. 1 mysql mysql 2048 Sep 16 00:43 /usr/local/mysql/data/test/tb_member2.MYI
-rw-r-----. 1 mysql mysql 8614 Sep 16 21:12 /usr/local/mysql/data/test/tb_member3.frm
-rw-r-----. 1 mysql mysql 0 Sep 16 21:12 /usr/local/mysql/data/test/tb_member3.MYD
-rw-r-----. 1 mysql mysql 1024 Sep 16 21:12 /usr/local/mysql/data/test/tb_member3.MYI
-rw-r-----. 1 mysql mysql 8614 Sep 16 21:14 /usr/local/mysql/data/test/tb_member.frm
-rw-r-----. 1 mysql mysql 53 Sep 16 21:14 /usr/local/mysql/data/test/tb_member.MRG
II.分区
i.什么是分区
分区和分表相似,都是按照规则分解表。不同在于分表将大表分解为若干个独立的实体表,而分区是将数据分段划分在多个位置存放,分区后,表还是一张表,但数据散列到多个位置了。app
读写的时候操作的还是表名字,db
自动去组织分区的数据。
分区主要有两种形式:
水平分区
水平分区(Horizontal Partitioning
) 这种形式分区是对表的行进行分区,所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。
举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。
垂直分区
垂直分区(Vertical Partitioning
) 这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。
举个简单例子:一个包含了大text
和BLOB
列的表,这些text
和BLOB
列又不经常被访问,这时候就要把这些不经常使用的text
和BLOB
了划分到另一个分区,在保证它们数据相关性的同时还能提高访问速度。
ii.分区技术支持
在5.6之前,使用这个参数查看当将配置是否支持分区
1.查看mysql
是否支持分区
mysql> SHOW VARIABLES LIKE '%partition%';
+-----------------------+---------------+
|Variable_name | Value |
+-----------------------+---------------+
| have_partition_engine | YES |
+-----------------------+------------------+
如果是yes
表示你当前的配置支持分区
在5.6及以采用后,则采用如下方式进行查看
mysql> show plugins;
在显示结果中,可以看到partition
是ACTIVE
的,表示支持分区
下面我们先演示一个按照范围(range
)方式的表分区
创建range
分区表
mysql> use test2;
mysql> create table if not exist user (
-> id int not null auto_increment,
-> name varchar(30) not null default '',
-> sex int(1) not null default '0',
-> primary key(id)
-> )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
-> );
通过帮助查看help create table
查看到
partition_definition:
PARTITION partition_name
[VALUES
{LESS THAN {(expr | value_list) | MAXVALUE}
|
IN (value_list)}]
[[STORAGE] ENGINE [=] engine_name]
[COMMENT [=] 'comment_text' ]
[DATA DIRECTORY [=] 'data_dir']
[INDEX DIRECTORY [=] 'index_dir']
[MAX_ROWS [=] max_number_of_rows]
[MIN_ROWS [=] min_number_of_rows]
[TABLESPACE [=] tablespace_name]
[(subpartition_definition [, subpartition_definition] ...)]
[DATA DIRECTORY [=] 'data_dir']
这里是指定分区存放的位置,要注意的是不要把这个路径指定为mysql
的数据存储路径,你的实验环境中就是/usr/local/mysql/data
,是不能放到这个data
目录下的。[INDEX DIRECTORY [=] 'index_dir']
这个是索引目录,注意这里使用的myisam
的存储引擎。而innodb
的数据和索引是在一个文件中,所以并不需要这个选项。
Subpartitions can be used with especially large MyISAM tables to distribute data and indexes across many disks. Suppose that you have 6 disks mounted as /disk0, /disk1, /disk2, and so on. Now consider the following example:
CREATE TABLE ts (id INT, purchased DATE)
ENGINE = MYISAM
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
PARTITION p0 VALUES LESS THAN (1990) (
SUBPARTITION s0
DATA DIRECTORY = '/disk0/data'
INDEX DIRECTORY = '/disk0/idx',
SUBPARTITION s1
DATA DIRECTORY = '/disk1/data'
INDEX DIRECTORY = '/disk1/idx'
),
PARTITION p1 VALUES LESS THAN (2000) (
SUBPARTITION s2
DATA DIRECTORY = '/disk2/data'
INDEX DIRECTORY = '/disk2/idx',
SUBPARTITION s3
DATA DIRECTORY = '/disk3/data'
INDEX DIRECTORY = '/disk3/idx'
),
PARTITION p2 VALUES LESS THAN MAXVALUE (
SUBPARTITION s4
DATA DIRECTORY = '/disk4/data'
INDEX DIRECTORY = '/disk4/idx',
SUBPARTITION s5
DATA DIRECTORY = '/disk5/data'
INDEX DIRECTORY = '/disk5/idx'
)
);
当你创建完成之后,你可以去你/usr/local/mysql/data
下面查看,你会发现有很多软连接,这些链接的位置,就是你指定的分区存储的位置。
插入些数据
mysql> insert into test2.user(name,sex)values ('tom1','0');
mysql> insert into test2.user(name,sex)values ('tom2','1');
mysql> insert into test2.user(name,sex)values ('tom3','1');
mysql> insert into test2.user(name,sex)values ('tom4','0');
mysql> insert into test2.user(name,sex)values ('tom5','0');
mysql> insert into test2.user(name,sex)values ('tom6','1');
mysql> insert into test2.user(name,sex)values ('tom7','1');
mysql> insert into test2.user(name,sex)values ('tom8','1');
mysql> insert into test2.user(name,sex)values ('tom9','1');
mysql> insert into test2.user(name,sex)values ('tom10','1');
mysql> insert into test2.user(name,sex)values ('tom11','1');
mysql> insert into test2.user(name,sex)values ('tom12','1');
mysql> insert into test2.user(name,sex)values ('tom13','1');
mysql> insert into test2.user(name,sex)values ('tom14','1');
到存放数据库表文件的地方看一下
[root@localhost ~]# ls -l /usr/local/mysql/data/test2/user*
-rw-r-----. 1 mysql mysql 8614 Sep 16 21:46 /usr/local/mysql/data/test2/user.frm
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:48 /usr/local/mysql/data/test2/user#P#p0.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:48 /usr/local/mysql/data/test2/user#P#p1.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:49 /usr/local/mysql/data/test2/user#P#p2.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:49 /usr/local/mysql/data/test2/user#P#p3.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:49 /usr/local/mysql/data/test2/user#P#p4.ibd
mysql> select count(id) as count from user;
+-------+
| count |
+-------+
| 14 |
+-------+
1 row in set (0.00 sec)
从某个分区中查询数据
mysql> select * from test2.user partition(p0);
2.新增分区
mysql> alter table test2.user add partition (partition partionname values less than (n));
3.删除分区
当删除了一个分区,也同时删除了该分区中所有的数据。
ALTER TABLE test2.user DROP PARTITION p3;
4.分区的合并
下面的SQL
,将p1 – p3
合并为2个分区p01 – p02
mysql> alter table test2.user
-> reorganize partition p1,p2,p3 into
-> (partition p01 values less than (8),
-> partition p02 values less than (12)
-> );
[root@localhost ~]# ls -l /usr/local/mysql/data/test2/user*
-rw-r-----. 1 mysql mysql 8614 Sep 16 22:06 /usr/local/mysql/data/test2/user.frm
-rw-r-----. 1 mysql mysql 98304 Sep 16 22:06 /usr/local/mysql/data/test2/user#P#p01.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 22:06 /usr/local/mysql/data/test2/user#P#p02.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:48 /usr/local/mysql/data/test2/user#P#p0.ibd
-rw-r-----. 1 mysql mysql 98304 Sep 16 21:49 /usr/local/mysql/data/test2/user#P#p4.ibd
mysql> select * from test2.user partition(p01);
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 3 | tom3 | 1 |
| 4 | tom4 | 0 |
| 5 | tom5 | 0 |
| 6 | tom6 | 1 |
| 7 | tom7 | 1 |
+----+------+-----+
5 rows in set (0.00 sec)
iii.mysql
分区的类型
1.RANGE
分区
range
官网https://dev.mysql.com/doc/refman/5.5/en/partitioning-range.html)
基于属于一个给定连续区间的列值,把多行分配给分区。这些区间要连续且不能相互重叠,使用VALUES LESS THAN
操作符来进行定义。以下是实例。
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
partition BY RANGE (store_id) (
partition p0 VALUES LESS THAN (6),
partition p1 VALUES LESS THAN (11),
partition p2 VALUES LESS THAN (16),
partition p3 VALUES LESS THAN (21)
);
按照这种分区方案,在商店1到5工作的雇员相对应的所有行被保存在分区P0中,商店6到10的雇员保存在P1中,依次类推。注意,每个分区都是按顺序进行定义,从最低到最高。
对于包含数据(72, 'Michael', 'Widenius', '1998-06-25', NULL, 13
)的一个新行,可以很容易地确定它将插入到p2分区中,但是如果增加了一个编号为第21的商店,将会发生什么呢?在这种方案下,由于没有规则把store_id
大于20的商店包含在内,服务器将不知道把该行保存在何处,将会导致错误。 要避免这种错误,可以创建maxvalue
分区,所有不在指定范围内的记录都会被存储到maxvalue
所在的分区中。
mysql> alter table test2.user add partition (partition p4 values less than maxvalue);
2.LIST
分区
类似于按RANGE
分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。
LIST
分区通过使用PARTITION BY LIST(expr)
来实现,其中“expr” 是某列值或一个基于某个列值、并返回一个整数值的表达式,然后通过VALUES IN (value_list)
的方式来定义每个分区,其中value_list
是一个通过逗号分隔的整数列表。
要按照属于同一个地区商店的行保存在同一个分区中的方式来分割表,可以使用下面的CREATE TABLE
语句:
Region | Store ID Numbers |
---|---|
North | 3, 5, 6, 9, 17 |
East | 1, 2, 10, 11, 19, 20 |
West | 4, 12, 13, 14, 18 |
Central | 7, 8, 15, 16 |
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
这使得在表中增加或删除指定地区的雇员记录变得容易起来。例如,假定西区的所有音像店都卖给了其他公司。那么与在西区音像店工作雇员相关的所有记录(行)可以使用查询ALTER TABLE employees DROP PARTITION pWest;
来进行删除,它与具有同样作用的DELETE (删除)查询DELETE query DELETE FROM employees WHERE store_id IN (4,12,13,14,18);
比起来,要有效得多。
要点:如果试图插入列值不在分区值列表中的一行时,那么INSERT
查询将失败并报错。例如,假定LIST
分区的采用上面的方案,下面的插入将失败:
INSERT INTO employees VALUES(224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 42, 21);
这是因为store_id
列值21不能在用于定义分区pNorth
, pEast
, pWest
,或pCentral
的值列表中找到。要重点注意的是,LIST分区没有类似如VALUES LESS THAN MAXVALUE
这样的包含其他值在内的定义。将要匹配的任何值都必须在值列表中找到。
3.HASH
分区
这种模式允许DBA
通过对表的一个或多个列的Hash Key
进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。
hash分区的目的是将数据均匀的分布到预先定义的各个分区中,保证各分区的数据量大致一致。
mysql> create table t_hash( a int(11), b datetime) partition by hash(year(b)) partitions 4;
has的分区函数页需要返回一个整数值。partitions
子句中的值是一个非负整数,不加的partitions
子句的话,默认为分区数为1
。
4.key
分区
key分区和hash分区相似,不同在于hash分区是用户自定义函数进行分区,key分区使用mysql数据库提供的函数进行分区,NDB cluster使用MD5函数来分区,对于其他存储引擎mysql使用内部的hash函数。
mysql> create table t_key( a int(11), b datetime) partition by key(b) partitions 4;
上面的RANGE
、LIST
、HASH
、KEY
四种分区中,分区的条件必须是整形,如果不是整形需要通过函数将其转换为整形。
5.columns
分区
mysql-5.5
开始支持COLUMNS
分区,可视为RANGE和LIST分区的进化,COLUMNS
分区可以直接使用非整形数据进行分区。COLUMNS
分区支持以下数据类型:
所有整形,如INT SMALLINT TINYINT BIGINT
。FLOAT
和DECIMAL
则不支持。
日期类型,如DATE
和DATETIME
。其余日期类型不支持。
字符串类型,如CHAR
、VARCHAR
、BINARY
和VARBINARY
。BLOB
和TEXT
类型不支持。
COLUMNS
可以使用多个列进行分区。
III.mysql
分表和分区有什么区别呢
i.实现方式上
a) mysql
的分表是真正的分表,一张表分成很多表后,每一个小表都是完整的一张表,都对应三个文件,一个.MYD
数据文件,.MYI
索引文件,.frm
表结构文件。
b) 分区不一样,一张大表进行分区后,他还是一张表,不会变成二张表,但是他存放数据的区块变多了
ii.数据处理上
a)分表后,数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。 b)分区呢,不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表呢,还是一张表,数据处理还是由自己来完成。
iii.提高性能上
a)分表后,单表的并发能力提高了,磁盘I/O
性能也提高了。并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出现高并发的话,总表可以根据不同的查询,将并发压力分到不同的小表里面。
b)mysql
提出了分区的概念,主要是想突破磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql
性能。
在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql
并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql
性能的目的。
iv.实现的难易度上
a)分表的方法有很多,用merge
来分表,是最简单的一种方式。这种方式跟分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。
b)分区实现是比较简单的,建立分区表,根建平常的表没什么区别,并且对开代码端来说是透明的。
IV.mysql
分表和分区有什么联系?
- 1.都能提高
mysql
的性高,在高并发状态下都有一个良好的表现。 - 2.分表和分区不矛盾,可以相互配合的,对于那些大访问量,并且表数据比较多的表,我们可以采取分表和分区结合的方式,访问量不大,但是表数据很多的表,我们可以采取分区的方式等。
- 3.分表技术是比较麻烦的,需要手动去创建子表,
app
服务端读写时候需要计算子表名。采用merge
好一些,但也要创建子表和配置子表间的union
关系。 - 4.表分区相对于分表,操作方便,不需要创建子表。