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

Mysql --分区表(2)

2016-08-09 15:10 155 查看

分区类型

RANGE分区

range分区的表是利用取值范围将数据分成分区,区间要连续并且不能互相重叠,使用values less than操作符进行分区定义

LIST分区

LIST分区是建立离散的值列表告诉数据库特定的值属于哪个分区,LIST分区在很多方面类似于RANGE分区,区别在LIST分区是从属于一个枚举列表的值得集合,RANGE分区是从属于一个连续区间值得集合。

LIST分区通过使用PARTITION BY LIST(expr)子句来实现,expr是某列值或一个局域某列值返回一个整数值得表达式,然后通过VALUES IN(value_list)的方式来定义分区,其中value_list是一个逗号分隔的整数列表。与RANGE分区不同,LIST分区不必声明任何特定顺序

HASH分区

HASH分区主要用来分散热点读,确保数据在预先确定个数的分区中尽可能平均分布。对一个表执行HASH分区时,MySQL会对分区键应用一个散列函数,以此确定数据应当放在N个分区中的哪个分区

MySQL支持两种HASH分区,常规HASH分区和线性HASH分区(LINEAR HASH);常规HASH使用的是取模算法,线性HASH分区使用的是一个线性的2的幂的运算法则

Key分区

按照Key进行分区非常类似于按照HASH进行分区,只不过HASH分区允许使用用户自定义的表达式,而Key分区不允许使用用户自定义的表达式,需要使用MySQL提供的HASH函数

数据库分区的一个非常常见的用途是按日期分离数据,一些数据库系统支持明确的日期分区,然而Mysql5.7并不支持(明确的)。然后使用DATE, TIME, or DATETIME 列来分区并不是什么难事儿,甚至基于表达式利用这样的列来创建分区。

当通过partition by KEY或LINEAR KEY的方式分区,你可以直接使用 DATE, TIME, or DATETIME column列作为分区键而不用对它们进行任何处理。

CREATE TABLE members (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY KEY(joined)
PARTITIONS 6;

创建一个存储过程插入一些数据
delimiter $$
drop procedure if exists pr_insertdate$$
create procedure pr_insertdate(in begindate date,in enddate date)
begin
while begindate<enddate
do
insert into members values('fan','boshi','duyalan',null,begindate);
set begindate = date_add(begindate,interval 1 day);
end while;
end$$

delimiter ;

调用存储过程插入数据
mysql> call pr_insertdate('2015-01-01','2016-08-08');
Query OK, 1 row affected (0.06 sec)

mysql> select count(*) from  members;
+----------+
| count(*) |
+----------+
|      585 |
+----------+
1 row in set (0.00 sec)

查看数据分布
select
partition_name part,
partition_expression expr,
partition_description descr,
table_rows
from information_schema.partitions  where
table_schema = schema()
and table_name='members';

+------+----------+-------+------------+
| part | expr     | descr | table_rows |
+------+----------+-------+------------+
| p0   | `joined` | NULL  |        177 |
| p1   | `joined` | NULL  |          0 |
| p2   | `joined` | NULL  |        208 |
| p3   | `joined` | NULL  |          0 |
| p4   | `joined` | NULL  |        200 |
| p5   | `joined` | NULL  |          0 |
+------+----------+-------+------------+
6 rows in set (0.00 sec)
然而根据我的实验这种分区貌似没什么卵子用,p1 p3 p5都用不上。这种分区方法也不能很好地利用分区裁剪特性


MySQL 5.6也支持 DATE or DATETIME 类型列进行range和list分区

CREATE TABLE members_year (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY RANGE( YEAR(joined) ) (
PARTITION p0 VALUES LESS THAN (1960),
PARTITION p1 VALUES LESS THAN (1970),
PARTITION p2 VALUES LESS THAN (1980),
PARTITION p3 VALUES LESS THAN (1990),
PARTITION p4 VALUES LESS THAN MAXVALUE
);
普通的range和list分区还是要被分区键列转换成整型

创建一个可以传入表名的过程,用到了prepare statement,因为表名无法作为参数传递
delimiter $$
drop procedure if exists pr_insertdate_1$$
create procedure pr_insertdate_1(in begindate date,in enddate date,in tabname varchar(40))
begin
while begindate<enddate
do
set @s=concat_ws(' ','insert into',tabname,'values(''fan'',''boshi'',''duyalan'',null,''',begindate,''')');
prepare stmt from @s;
execute stmt;
drop prepare stmt;
set begindate = date_add(begindate,interval 1 day);
end while;
end$$

delimiter ;

调用存储过程插入数据
mysql> call pr_insertdate_1('1960-01-01','1990-12-31','members_mon');
Query OK, 0 rows affected (3.17 sec)

mysql> select count(*) from members_year;
+----------+
| count(*) |
+----------+
|    11322 |
+----------+
1 row in set (0.01 sec)

查看数据分布
select
partition_name part,
partition_expression expr,
partition_description descr,
table_rows
from information_schema.partitions  where
table_schema = schema()
and table_name='members_year';

+------+---------------+----------+------------+
| part | expr          | descr    | table_rows |
+------+---------------+----------+------------+
| p0   |  YEAR(joined) | 1960     |          0 |
| p1   |  YEAR(joined) | 1970     |       3653 |
| p2   |  YEAR(joined) | 1980     |       3652 |
| p3   |  YEAR(joined) | 1990     |       3653 |
| p4   |  YEAR(joined) | MAXVALUE |        364 |
+------+---------------+----------+------------+

查看是否可以使用到分区裁剪特性
mysql> explain partitions select * from members_year where joined='1970-02-01';
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | members_year | p2         | ALL  | NULL          | NULL | NULL    | NULL | 3652 | Using where |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


分区表可以指定DATA Directory Directory

对于myisam表可以还可以指定index directory

CREATE TABLE users_myisam (
uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL DEFAULT '',
email VARCHAR(30) NOT NULL DEFAULT ''
)  engine=myisam
PARTITION BY RANGE (uid) (
PARTITION p0 VALUES LESS THAN (10)
DATA DIRECTORY = '/data/data1'
INDEX DIRECTORY = '/data/idx1',
PARTITION p1 VALUES LESS THAN (20)
DATA DIRECTORY = '/data/data2'
INDEX DIRECTORY = '/data/idx2'
);

[root@uz6535 fandb]# ls -l /data/mysql55/fandb|grep users_myisam
-rw-r----- 1 mysql mysql     8620 May 18 09:09 users_myisam.frm
-rw-r----- 1 mysql mysql       28 May 18 09:09 users_myisam.par
lrwxrwxrwx 1 mysql mysql       33 May 18 09:09 users_myisam#P#p0.MYD -> /data/data1/users_myisam#P#p0.MYD
lrwxrwxrwx 1 mysql mysql       32 May 18 09:09 users_myisam#P#p0.MYI -> /data/idx1/users_myisam#P#p0.MYI
lrwxrwxrwx 1 mysql mysql       33 May 18 09:09 users_myisam#P#p1.MYD -> /data/data2/users_myisam#P#p1.MYD
lrwxrwxrwx 1 mysql mysql       32 May 18 09:09 users_myisam#P#p1.MYI -> /data/idx2/users_myisam#P#p1.MYI


对于innodb表,只能指定data directory参数

CREATE TABLE users_innodb (
uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL DEFAULT '',
email VARCHAR(30) NOT NULL DEFAULT ''
)
PARTITION BY RANGE (uid) (
PARTITION p0 VALUES LESS THAN (10)
DATA DIRECTORY = '/data/data1',
PARTITION p1 VALUES LESS THAN (20)
DATA DIRECTORY = '/data/data2'
);


在指定的路径下会创建 库名文件夹

[root@uz6535 fandb]# ls -l /data/data1/fandb/users_innodb*
-rw-r----- 1 mysql mysql 98304 May 18 09:09 /data/data1/fandb/users_innodb#P#p0.ibd
[root@uz6535 fandb]# ls -l /data/data2/fandb/users_innodb*
-rw-r----- 1 mysql mysql 98304 May 18 09:09 /data/data2/fandb/users_innodb#P#p1.ibd


在datadir/库名 下包含frm文件和isl文件

[root@uz6535 fandb]# ls -l /data/mysql55/fandb/users_innodb*
-rw-r----- 1 mysql mysql 8620 May 18 09:09 /data/mysql55/fandb/users_innodb.frm
-rw-r----- 1 mysql mysql   39 May 18 09:09 /data/mysql55/fandb/users_innodb#P#p0.isl
-rw-r----- 1 mysql mysql   39 May 18 09:09 /data/mysql55/fandb/users_innodb#P#p1.isl


isl文件是一个文本文件,指明了分区ibd文件实际存储路径

[root@uz6535 fandb]# file /data/mysql55/fandb/users_innodb#P#p0.isl
/data/mysql55/fandb/users_innodb#P#p0.isl: ASCII text, with no line terminators
[root@uz6535 fandb]# more /data/mysql55/fandb/users_innodb#P#p0.isl
/data/data1/fandb/users_innodb#P#p0.ibd
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mysql