MySQL自5.1开始对分区(Partition)有支持。

= 水平分区(根据列属性按行分)=
举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。

水平分区的几种模式:

* Range(范围) –  基于属于一个给定连续区间的列值,把多行分配给分区。例如DBA可以将一个表通过年份划分成三个分区,80年代(1980's)的数据,90年代(1990's)的数据以及任何在2000年(包括2000年)后的数据。

RANGE分区基于一个给定的连续区间范围,早期版本RANGE主要是基于整数的分区。在5.7版本中DATE、DATETIME列也可以使用RANGE分区,同时在5.5以上的版本提供了基于非整形的RANGE COLUMN分区。RANGE分区必须的连续的且不能重叠。使用"VALUES LESS THAN ()" 来定义分区区间,非整形的范围值需要使用单引号,并且可以使用MAXVALUE作为分区的最高值。

List(预定义列表) –  类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。

* Hash(哈希) –  基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。例如DBA可以建立一个对表主键进行分区的表。

* Key(键值) – 上面Hash模式的一种延伸,这里的Hash Key是MySQL自身的哈希函数产生的。

* COLUMNS –  MYSQL5.5开始支持COLUMNS分区,可视为RANGE和LIST分区的一个进化。COLUMNS分区可以直接使用非整型的数据进行分区,分区根据类型直接比较而得到,不需要转化为整型。COLUMNS分区支持以下数据类型:

  • 所有的整型类型,如INT,TINYINT,SMALLINT,BIGINT。对FLOAT和DECIMAL不支持
  • 日期类型,DATE,DATETIME。其余日期类型不支持。
  • 字符串类型,如CHAR,VARCHAR,BINARY,VARBINARY。不支持BLOB和TEXT。

* Composite(复合模式) - 很神秘吧,哈哈,其实是以上模式的组合使用而已,就不解释了。举例:在初始化已经进行了Range范围分区的表上,我们可以对其中一个分区再进行hash哈希分区。

= 垂直分区(按列分)=
举个简单例子:一个包含了大text和BLOB列的表,这些text和BLOB列又不经常被访问,这时候就要把这些不经常使用的text和BLOB了划分到另一个分区,在保证它们数据相关性的同时还能提高访问速度。MySQL目前不支持垂直分区。

Range 分区

创建分区

  1. CREATE DATABASE part;
    CREATE TABLE e (
  2. id INT NOT NULL,
  3. fname VARCHAR(30),
  4. lname VARCHAR(30)
  5. )
  6. PARTITION BY RANGE (id) (
  7. PARTITION p0 VALUES LESS THAN (50),
  8. PARTITION p1 VALUES LESS THAN (100),
  9. PARTITION p2 VALUES LESS THAN (150),
  10. PARTITION p3 VALUES LESS THAN (MAXVALUE)
  11. );
  1. INSERT INTO e VALUES
  2. (1669, "Jim", "Smith"),
  3. (337, "Mary", "Jones"),
  4. (16, "Frank", "White"),
  5. (2005, "Linda", "Black");

查看分区和分区的行数:

  1. root@localhost 20:15:26[part]> SELECT PARTITION_NAME, TABLE_ROWS
  2. -> FROM INFORMATION_SCHEMA.PARTITIONS
  3. -> WHERE TABLE_NAME = 'e';
  4. +----------------+------------+
  5. | PARTITION_NAME | TABLE_ROWS |
  6. +----------------+------------+
  7. | p0 | 1 |
  8. | p1 | 0 |
  9. | p2 | 0 |
  10. | p3 | 3 |
  11. +----------------+------------+
  12.  
  13. > SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = 'part' AND TABLE_NAME LIKE 'e'; 

删除某个分区,不仅分区结构会被删除,分区里的数据也会被删除:

  1. ALTER TABLE e DROP PARTITION p0;

增加分区:

  1. > alter table e add partition (partition p4 values less than (5600));
  2. ERROR 1481 (HY000): MAXVALUE can only be used in last partition definition

说明有MAXVALUE值后,直接加分区是不可行的,需要使用 reorginize partition() 重新组织分区。且 RANGE 分区在加分区的时候,只能从最大值后面加,而最大值前面不可以添加。

也可以重新组织分区,重组分区的做法是,把原来的分区结构删除,创建新的分区结构,但新的分区结构必须要能容纳原分区的数据,否则会有报错:ERROR 1526 (HY000): Table has no partition for value 1234

  1. # 把原range分区,重组为list分区,此过程不会丢失数据
  2. > alter table e partition by list(id)(PARTITION a VALUES IN (1,5,6,1669,2005),PARTITION b VALUES IN (1234,2,7,8,337,9898));
  3. Query OK, 7 rows affected (0.12 sec)
  4. Records: 7 Duplicates: 0 Warnings: 0

如果在一个没有分区定义的表中增加分区,直接使用 add 添加会报错:

  1. > alter table e add partition (partition p0 values less than(50),PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN (150));
  2. ERROR 1505 (HY000): Partition management on a not partitioned table is not possible

可以使用 partition by 新建:

  1. > alter table e partition by range(id)(PARTITION p1 VALUES LESS THAN (100),PARTITION p2 VALUES LESS THAN (1256320));
  2. Query OK, 7 rows affected (0.08 sec)
  3. Records: 7 Duplicates: 0 Warnings: 0

也可以新建一个具有分区的表,结构一致,然后用insert into 分区表 select * from 原始表;

LIST 分区

创建 list 分区:

  1. CREATE TABLE tblist (
  2. id INT NOT NULL,
  3. store_id INT
  4. )
  5. PARTITION BY LIST(store_id) (
  6. PARTITION a VALUES IN (1,5,6),
  7. PARTITION b VALUES IN (2,7,8),
  8. PARTITION c VALUES IN (3,9,10),
  9. PARTITION d VALUES IN (4,11,12)
  10. );
  11.  
  12. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='tblist';

增加分区:

  1. ALTER TABLE tblist ADD PARTITION (PARTITION e VALUES IN (20));
  2. # 注意:不能增加包含现有任意值的分区。

合并分区:

  1. ALTER TABLE tblist REORGANIZE PARTITION a,b INTO (PARTITION m VALUES IN (1,5,6,2,7,8,13));
    # 将分区a,b合并为分区m
  2. # 可以新增值,例如这里增加了 13 值
    # 注意:同 RANGE 分区一样,只能合并相邻的几个分区,不能跨分区合并。例如不能合并a,c两个分区,只能通过合并a,b,c

拆分分区:

  1. ALTER TABLE tblist REORGANIZE PARTITION m,c INTO
  2. (PARTITION m VALUES IN (1,5,6,3,9,10),
  3. PARTITION n VALUES IN (2,7,8));

注意

1. 在5.7.12版本中测试发现,合并和拆分分区重新定义的枚举值可以不是原来的值,如果原来的枚举值包含了数据而新合并或拆分的分区枚举值又不不包含原来的枚举值会造成数据丢失。虽然不知道为什么mysql不会禁止该行为,但是人为的要求无论是合并还是拆分分区枚举值保持不变,或者只能增加不能减少,这样能保证数据不丢失。

2. 并和拆分后的分区由于是相邻的分区进行合并和拆分会根据原本的分区的值新的分区也会在原本的分区的顺序位置。

3. 分区的语法基本是一致的,只是定义分区范围略有不同。如 RANGE 分区采用: VALUES LESS THAN (value),而 LIST 分区采用: VALUES IN (list) 。

删除分区:

  1. ALTER TABLE tblist DROP PARTITION e;
  2. # 注意:删除分区同时会将分区中的数据删除,同时枚举的list值也被删除,后面无法往表中插入该值的数据。

HASH 分区

基于给定的分区个数,将数据分配到不同的分区,HASH分区只能针对整数进行HASH,对于非整形的字段只能通过表达式将其转换成整数。表达式可以是mysql中任意有效的函数或者表达式,对于非整形的HASH往表插入数据的过程中会多一步表达式的计算操作,所以不建议使用复杂的表达式这样会影响性能。

MYSQL支持两种HASH分区,常规HASH(HASH)和线性HASH(LINEAR HASH) 。

1. 常规HASH

常规hash是基于分区个数的取模(%)运算。根据余数插入到指定的分区。

  1. CREATE TABLE tbhash (
  2. id INT NOT NULL,
  3. store_id INT
  4. )
  5. PARTITION BY HASH(store_id)
  6. PARTITIONS 4;
  7.  
  8. ALTER TABLE tbhash ADD INDEX ix_store_id(store_id);
  9.  
  10. INSERT INTO tbhash() VALUES(1,100),(1,101),(2,102),(3,103),(4,104);
  11.  
  12. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME
  13. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='tbhash';

时间字段类型分区:

  1. CREATE TABLE employees (
  2. id INT NOT NULL,
  3. hired DATE NOT NULL DEFAULT '1970-01-01',
  4. )
  5. PARTITION BY HASH( YEAR(hired) )
  6. PARTITIONS 4;

常规hash的分区非常的简便,通过取模的方式可以让数据非常平均的分布每一个分区,但是由于分区在创建表的时候已经固定了。如果新增或者收缩分区的数据迁移比较大。

2. 线性HASH(LINEAR HASH)

LINEAR HASH和HASH的唯一区别就是PARTITION BY LINEAR HASH。

  1. CREATE TABLE tblinhash (
  2. id INT NOT NULL,
  3. hired DATE NOT NULL DEFAULT '1970-01-01'
  4. )
  5. PARTITION BY LINEAR HASH( YEAR(hired) )
  6. PARTITIONS 6;

线性HASH的计算原理参考:http://www.cnblogs.com/chenmh/p/5644496.html

3. 分区管理

减去3个分区:

  1. ALTER TABLE tblinhash COALESCE PARTITION 3;
  2.  
  3. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME
  4. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='tblinhash';

注意:减去两个分区后,数据根据现有的分区进行了重新的分布,以'2003-04-14'为例:POWER(2, CEILING( LOG(2,3) ))=4,2003&(4-1)=3,3>=3,3&(CEILING(3/2)-1)=1,所以现在的'2003-04-14'这条记录由原来的p3变成了p1。

增加4个分区:

  1. ALTER TABLE tblinhash add PARTITION partitions 4;
  2.  
  3. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME
  4. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='tblinhash';

当在3个分区的基础上增加4个分区后,‘2003-04-14’由原来的p1变成了p3,而另一条记录由原来的p2变成了p6。

KEY分区

KEY分区和HASH分区相似,但是KEY分区支持除text和BLOB之外的所有数据类型的分区,而HASH分区只支持数字分区,KEY分区不允许使用用户自定义的表达式进行分区,KEY分区使用系统提供的HASH函数进行分区。当表中存在主键或者唯一键时,如果创建key分区时没有指定字段系统默认会首选主键列作为分区字列,如果不存在主键列会选择非空唯一键列作为分区列,注意唯一列作为分区列唯一列不能为null。

创建常规 KEY 分区

  1. CREATE TABLE tb_key (
  2. id INT ,
  3. var CHAR(32)
  4. )
  5. PARTITION BY KEY(var)
  6. PARTITIONS 10;
  7.  
  8. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME
  9. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='tb_key';

创建 LINEAR KEY 分区

同样key分区也存在线性KEY分区,概念和线性HASH分区一样。

  1. CREATE TABLE tb_keyline (
  2. id INT NOT NULL,
  3. var CHAR(5)
  4. )
  5. PARTITION BY LINEAR KEY (var)
  6. PARTITIONS 3;

COLUMN 分区

COLUMN分区是5.5开始引入的分区功能,只有RANGE COLUMN和LIST COLUMN这两种分区;支持整形、日期、字符串;同RANGE和LIST的分区方式非常的相似。

COLUMNS和RANGE和LIST分区的区别

1. 针对日期字段的分区就不需要再使用函数进行转换了,例如针对date字段进行分区不需要再使用YEAR()表达式进行转换。

2. COLUMN分区支持多个字段作为分区键但是不支持表达式作为分区键。

COLUMNS支持的类型

整形支持:tinyint,smallint,mediumint,int,bigint;不支持decimal和float

时间类型支持:date,datetime

字符类型支持:char,varchar,binary,varbinary;不支持text,blob

一、RANGE COLUMNS分区

1. 日期字段分区

  1. CREATE TABLE members (
  2. id INT,
  3. joined DATE NOT NULL
  4. )
  5. PARTITION BY RANGE COLUMNS(joined) (
  6. PARTITION a VALUES LESS THAN ('1960-01-01'),
  7. PARTITION b VALUES LESS THAN ('1970-01-01'),
  8. PARTITION c VALUES LESS THAN ('1980-01-01'),
  9. PARTITION d VALUES LESS THAN ('1990-01-01'),
  10. PARTITION e VALUES LESS THAN MAXVALUE
  11. );
  1. insert into members(id,joined) values(1,'1950-01-01'),(1,'1960-01-01'),(1,'1980-01-01'),(1,'1990-01-01');
  1. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME,SUBPARTITION_METHOD,SUBPARTITION_EXPRESSION
  2. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='members';

2. 多字段组合分区

  1. CREATE TABLE rcx (
  2. a INT,
  3. b INT
  4. )
  5. PARTITION BY RANGE COLUMNS(a,b) (
  6. PARTITION p0 VALUES LESS THAN (5,10),
  7. PARTITION p1 VALUES LESS THAN (10,20),
  8. PARTITION p2 VALUES LESS THAN (15,30),
  9. PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE)
  10. );

注意:

1)多字段的分区键比较是基于数组的比较。它先用插入的数据的第一个字段值和分区的第一个值进行比较,如果插入的第一个值小于分区的第一个值那么就不需要比较第二个值就属于该分区;如果第一个值等于分区的第一个值,开始比较第二个值同样如果第二个值小于分区的第二个值那么就属于该分区。

2)RANGE COLUMN的多列分区第一列的分区值一定是顺序增长的,不能出现交叉值,第二列的值随便,例如以下分区就会报错。

二、LIST COLUMNS分区

1. 非整形字段分区

  1. CREATE TABLE listvar (
  2. id INT NOT NULL,
  3. hired DATETIME NOT NULL
  4. )
  5. PARTITION BY LIST COLUMNS(hired)
  6. (
  7. PARTITION a VALUES IN ('1990-01-01 10:00:00','1991-01-01 10:00:00'),
  8. PARTITION b VALUES IN ('1992-01-01 10:00:00'),
  9. PARTITION c VALUES IN ('1993-01-01 10:00:00'),
  10. PARTITION d VALUES IN ('1994-01-01 10:00:00')
  11. );
  12.  
  13. ALTER TABLE listvar ADD INDEX ix_hired(hired);
  14.  
  15. INSERT INTO listvar() VALUES(1,'1990-01-01 10:00:00'),(1,'1991-01-01 10:00:00'),(1,'1992-01-01 10:00:00'),(1,'1993-01-01 10:00:00');

LIST COLUMNS分区对分整形字段进行分区就无需使用函数对字段处理成整形,所以对非整形字段进行分区建议选择COLUMNS分区。

2. 多字段分区

  1. CREATE TABLE listvardou (
  2. id INT NOT NULL,
  3. hired DATETIME NOT NULL
  4. )
  5. PARTITION BY LIST COLUMNS(id,hired)
  6. (
  7. PARTITION a VALUES IN ( (1,'1990-01-01 10:00:00'),(1,'1991-01-01 10:00:00') ),
  8. PARTITION b VALUES IN ( (2,'1992-01-01 10:00:00') ),
  9. PARTITION c VALUES IN ( (3,'1993-01-01 10:00:00') ),
  10. PARTITION d VALUES IN ( (4,'1994-01-01 10:00:00') )
  11. );
  12.  
  13. ALTER TABLE listvardou ADD INDEX ix_hired(hired);
  14.  
  15. INSERT INTO listvardou() VALUES(1,'1990-01-01 10:00:00'),(1,'1991-01-01 10:00:00'),(2,'1992-01-01 10:00:00'),(3,'1993-01-01 10:00:00');
  16.  
  17. SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME,SUBPARTITION_METHOD,SUBPARTITION_EXPRESSION
  18. FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='listvardou';

移除表分区

  1. ALTER TABLE tablename REMOVE PARTITIONING ;

注意:使用remove移除分区是仅仅移除分区的定义,并不会删除数据和 drop PARTITION 不一样,后者会连同数据一起删除。

MySQL 分区简介的更多相关文章

  1. php面试专题---MySQL分区

    php面试专题---MySQL分区 一.总结 一句话总结: mysql的分区操作还比较简单,好处是也不用自己动手建表进行分区,和水平分表有点像 1.mysql分区简介? 一个表或索引-->N个物 ...

  2. mysql分区功能(三个文件储存一张表)(分区作用)(分区方式)

    mysql分区功能(三个文件储存一张表)(分区作用)(分区方式) 一.总结 1.mysql数据表的存储方式(三个文件储存一张表): 一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放 ...

  3. Atitit 分区后的查询  mysql分区记录的流程与原理

    Atitit 分区后的查询  mysql分区记录的流程与原理 1.1.1. ibd是MySQL数据文件.索引文件1 1.2. 已经又数据了,如何分区? 给已有的表加上分区 ]1 1.3. 分成4个区, ...

  4. MySQL分区总结

    MySQL支持RANGE,LIST,HASH和KEY四种分区.其中,每个分区又都有一种特殊的类型.对于RANGE分区,有RANGE COLUMNS分区.对于LIST分区,有LIST COLUMNS分区 ...

  5. Mysql 分区处理NULL的得方式

    MySQL分区处理NULL值得方式 一般情况下,MySQL的分区把NULL当做零值,或者一个最小值进行处理 对于range分区 create table test_null( id int ) par ...

  6. mysql分区及实例演示

    一.为什么要分区? 需求:大数据.解决方案:分而治之,更细一点即为.将大表和大索引分为一个更小的操作单元 在mysql中,分区允许将表.索引和索引编排表细分为更小的单元.分区后,每个分区有自己单独的名 ...

  7. mysql分区

    <?php /* 分区 目录 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. ...

  8. Mysql分区技术

    注:分区的语法可以看手册中有详细的写法和例子: show plugins; 此命令查看可有partition这个选项,有则mysql支持分区,没有的话,就可以升级一下mysql 实时监控一个命令执行情 ...

  9. 十五、mysql 分区之 分区管理

    1.mysql分区处理分区字段NULL值的方式 1.range分区null被当作最小值处理 2.list分区null值必须被枚举出来,否则将出错 3.hash/key分区 null值当作0处理 2.R ...

随机推荐

  1. 【BZOJ1064】[Noi2008]假面舞会 DFS树

    [BZOJ1064][Noi2008]假面舞会 Description 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择 ...

  2. 用EasyDarwin进行IPTV rtsp mpeg-ts smil流的转发和分发直播服务

    对RTSP/RTP的转发和分发一直都是EasyDarwin的基础功能,尤其是在安防行业中,EasyDarwin非常贴合安防监控的需求,但一直未尝试用EasyDarwin进行IPTV的RTSP流进行转发 ...

  3. Spring整合Hibernate的方法

    一.基本支持 Spring 支持大多数流行的 ORM 框架, 包括 Hibernate JDO, TopLink, Ibatis 和 JPA. Spring 对这些 ORM 框架的支持是一致的, 因此 ...

  4. mybatis入门(十)

    mybatis和hibernate本质区别和应用场景 hibernate:是一个标准ORM框架(对象关系映射).入门门槛较高的,不需要程序写sql,sql语句自动生成了. 对sql语句进行优化.修改比 ...

  5. cenos 6.5 安装apache 2.4.28出现种问题

    编译出错 configure: error: APR-util not found. Please read the documentation 解决办法 wget http://apache.fre ...

  6. hdu 3415 单调队列

    Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  7. appium导入哪些java模块

    简单介绍 讲解一个appium测试脚本需要导入哪些java模块. 导入的java模块 明确两点信息: 一个脚本需要讲清楚测试环境:1.自动化平台方面,测试的平台是什么(appium或者selendro ...

  8. Eclipse快捷键【转载】

    分享一前辈的博客-Eclipse快捷键

  9. 自动化测试框架selenium+java+TestNG——配置篇

    最近来总结下自动化测试 selenium的一些常用框架测试搭配,由简入繁,最简单的就是selenium+java+TestNG了,因为我用的是java,就只是总结下java了. TestNG在线安装: ...

  10. git比较两个版本,获取所有代码有差别的文件,并拷贝到一个文件夹中

    git diff 3b3855d a024af5 --name-only | xargs -i cp '{}' ./update/ --parents 解释:通过xargs 命令,把git diff  ...