MySQL中的分区

MySQL从5.1版本开始支持分区功能,它允许可设置的一定逻辑,跨文件系统分配单个表的多个部分,但是就访问数据库而言,逻辑上还是只有一个表。

一、什么是分区?

一开始也讲了,根据一定逻辑规则,将一个表拆成多个更小更容易管理的部分。例如我们新建一张表利用range分区


image.png

image.png

逻辑上还是只有一张表,但是实际上确有3个物理分区对象组成
我们查看是否支持分区时对于5.6以下的版本可以使用如下命令:
show variables like '%partition%';
而在5.6及以上用如上命令会显示empty set,但是并不是表示不支持分区,而是我们应该这样查看:
show plugins;
当看到有partition并且status是active时表示支持。

二、为什么分区?好处在哪?

1、分区可以在一个表中存储比单个磁盘或文件系统分区上的数据更多的数据,因为我们可以将分区表存储在不同物理磁盘上

2、对已过期或者不需要保存的数据,可以通过删除与这些数据有关的分区来快速删除数据,他的效率远比delete高;

3、优化查询,在where子句中包含分区条件时,可以只扫描必要的一个或者多个分区来提高查询效率;例如下面语句:

SELECT * FROM t PARTITION(p0,p1)WHERE c <5仅选择与WHERE条件匹配的分区p0和p1中的那些行。

在这种情况下,MySQL不检查表t的任何其他分区;

4、涉及聚合函数SUM()、COUNT()的查询时,可以容易的在每个分区上并行处理,例如在执行下面这条语句:

SELECT salesperson_id,COUNT(orders)as order_total FROM sales GROUP BY salesperson_id ;会在每个分区上都同时运行查询;

5、凭借在多个磁盘上传播数据,实现更高的查询吞吐量。

说这么多好处,也说一下它的缺点吧:

1、一个表最多只能有1024个分区;

2、在MySQL5.1中,分区表达式必须为整数或者返回整数,而在MySQL5.5以后可以使用非整数,即其他的数据类型(并不是所有的数据类型)来分区;

3、同一个分区表的所有分区必须使用相同存储引擎;

4、分区表无法使用外键约束;
> 1506 - Foreign keys are not yet supported in conjunction with partitioning

三、如何分区?

有以下四种分区类型:

1. RANGE分区:

基于一个给定连续区间范围,把数据分配到不同的分区;

2. LIST分区:

类似RANGE分区,区别在LIST分区是基于枚举出的值列表分区,RANGE是基于给定连续区间范围分区;

3. HASH分区:

基于用户定义的表达式返回值来选择分区,该表达式对要插入到表的行中列值操作;

4. KEY分区:

类似HASH,但是HASH允许使用用户自定义表达式,而KEY分区不允许,它需要使用MySQL服务器提供的HASH函数,同时HASH分区只支持整数分区,而KEY分区支持除BLOB和TEXT类型外其他列;

但是无论是哪一种分区类型,要么分区表上没有主键/唯一键,要么分区表的主键/唯一键都必须包含分区键,否则会报错:
A PRIMARY KEY must include all columns in the table's partitioning function

A UNIQUE INDEX must include all columns in the table's partitioning function

RANGE分区:

利用取值范围将数据分区,区间要连续并且不可以重叠,使用VALUES LESS THAN 进行分区定义,举例如下:

分别创建两张表,分区的没有分区的:

create table testwithoutpartition(
id int DEFAULT null,
name char(5),
datedata date
)

create table testwithpartition(
id int DEFAULT null,
name char(5),
datedata date
)

PARTITION BY RANGE (year(datedata)) (
PARTITION p1 VALUES LESS THAN (1996) ,
PARTITION p2 VALUES LESS THAN (1997) , 
PARTITION p3 VALUES LESS THAN (1998) ,
PARTITION p4 VALUES LESS THAN (1999) , 
PARTITION p5 VALUES LESS THAN (2000) ,
PARTITION p6 VALUES LESS THAN MAXVALUE );

上面分区语句的VALUES LESS THAN MAXVALUE子句是表示当有大于2000的时候都插入到p6中,MAXVALUE代表最大可能整数值,否则当我们插入一条记录包含2001时会报错;

从上面我们可以看到顺序是有规定的,当我们把p2设为1998而p3设为1997时会报错:
VALUES LESS THAN value must be strictly increasing for each partition
接着我们使用存储过程分别给两张表插入数据

CREATE DEFINER=`root`@`localhost` PROCEDURE `insertdata`()
BEGIN
    DECLARE numb int DEFAULT 0;
    while i < 20000
    do
        insert into testwithpartition values(numb,'lanco',DATE_ADD('1996-04-01',INTERVAL numb DAY));
        set numb =numb+1;
    end while;
END

当要删除过期的数据时候,只需要简单的语句如此来删除p0分区中的数据:

ALTER TABLE testwithpartition drop PARTITION p0

LIST分区:建立离散值列表指定特定值属于哪一个分区

create table testwithlistpartition(
id int not null,
name char(5),
category VARCHAR(30)
)
PARTITION BY LIST (id) (
PARTITION p0 VALUES IN (1,5) ,
PARTITION p1 VALUES IN (11,15) ,
PARTITION p2 VALUES IN (6,10) ,
PARTITION p3 VALUES IN (16,20)
);
image.png

如上,可以看出和RANGE分区不同的是,我们不必遵循特定的顺序,而如果我们试图插入的记录不在分区值列表中,他不像RANGE有VALUES LESS THAN MAXVALUE这样包含其它的值方式,


image.png

COLUMNS分区:

他是在MySQL5.5引入的分区类型,实际上就是为了解决RANGE和LIST分区只支持整数分区问题,COLUMNS可以细分为RANGE?COLUMNS和LIST?COLUMNS分区,他们都支持整数,日期时间,字符串三大数据类型:

1、所有的整数类型,int,tinyint,bigint等,但不支持decimal,float等;
2、日期时间类型:date和datetime;
3、字符类型:char,varchar,binary,varbinary;不支持text和blob类型;

但是要注意,Columns分区仅支持一个或者多个字段名作分区键,而不支持表达式作分区键,如上面的RANGE分区year(datadate),即使返回整型也不可以;

但是其中一大亮点是能够支持多列分区:
RANGE COLUMNS
我们先创建一个RANGE分区:

CREATE TABLE test1 (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS(a, b) (
    PARTITION p0 VALUES LESS THAN (5, 12),
    PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE)
);

那这样子我插入三条记录id=5,那他是插入到哪里呢?

INSERT INTO test1 VALUES (5,10), (5,11), (5,12);

我们如何查看他是插入到哪一个分区:

select partition_name part,
partition_expression expr,
partition_description descr,
table_rows
from
information_schema.partitions
where
TABLE_SCHEMA = schema()
and table_name='test1';
image.png

如图可以看出是插入到p1分区表里;继续写入一条记录,并且发现是写入到p3分区表里,

接着我们创建一个RANGE COLUMNS分区表:

CREATE TABLE rc1 (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS(a, b) (
    PARTITION p0 VALUES LESS THAN (5, 12),
    PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE)
);
image.png

依旧和test1表一样的三条数据插入,查看插入到哪里:

可以看出来两者对于数据插入的比较差别了吗?
这是因为我们比较的是元组值而非标量值,你看


image.png

例如我们这里插入的记录(5,10),它先取第一个值5与分区限制行值比较,因为p0(5,12),记录5不小于限制行值5,所以比较记录第二位10,他小于限制行值12,所以属于p0区,

假如我们又插入新数据(2,13),查看可知:

还是p0区,如此便清晰明了,它先用插入的数据的第一个字段值和分区的第一个值进行比较,如果插入的第一个值小于分区的第一个值那么就不需要比较第二个值就属于该分区;如果第一个值等于分区的第一个值,开始比较第二个值同样如果第二个值小于分区的第二个值那么就属于该分区。

LIST COLUMNS:

CREATE TABLE test3 (
    first_name VARCHAR(25),
    last_name VARCHAR(25),
    street_1 VARCHAR(30),
    street_2 VARCHAR(30),
    city VARCHAR(15),
    renewal DATE
)
PARTITION BY LIST COLUMNS(city) (
    PARTITION pRegion_1 VALUES IN('Oskarshamn', 'H?gsby', 'M?nster?s'),
    PARTITION pRegion_2 VALUES IN('Vimmerby', 'Hultsfred', 'V?stervik'),
    PARTITION pRegion_3 VALUES IN('N?ssj?', 'Eksj?', 'Vetlanda'),
    PARTITION pRegion_4 VALUES IN('Uppvidinge', 'Alvesta', 'V?xjo')
);

和RANGE COLUMNS一样,支持其他数据类型作分区键;

HASH分区:

基于给定的分区个数,将数据分配到不同分区,HASH分区只能对整数进行分区,对于非整型字段只能通过表达式转为整型,MySQL支持两种HASH分区-常规hash和线性hash。

例如创建如下hash分区表:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01'
)
PARTITION BY HASH( id )
PARTITIONS 4;

它表示根据id值hash分区,分区数为4,如果不包含PARTITIONS子句,则分区数缺省为1。

insert into employees
values(1,'liu','lanco','2018-05-01'),
(2,'liu','lanco','2018-05-02'),
(3,'liu','lanco','2018-05-03'),
(4,'liu','lanco','2018-05-04'),
(5,'liu','lanco','2018-05-05');

查看分区范围:


image.png

实际上常规的hash是基于取模运算进行判断新记录应该插入到哪一个分区,例如上面新记录id=2,运算表达式为mod(2,4)

常规的hash分区看起来挺不错的,但是当我们需要增加分区或者合并分区时候,问题就来了,这里有4个分区,现在需要增加一个分区,或者合并分区,原来的取模算法是MOD(expr,4),现在新增一个分区,取模算法变成MOD(expr,5),数据都要重新计算分区,这个代价实在太大了。

线性HASH分区:

线性HASH分区与常规HASH分区不同之处在于线性HASH使用线性的2的幂运算法则,并且分区关键字为LINEAR HASH。

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01'
)
PARTITION BY HASH( id )
PARTITIONS 4;

假设将要保存的记录分区编号为N,num是分区数,我们可以通过如下计算得到指定记录保存在哪一个分区:

1、找到下一个大于等于num的2次幂,这个值设为V ,可以通过如下公式

V =POWER(2,Ceilling(Log(2,num)));

2、其次,设置N=F(column_list)&(V-1)

例如上述给出的例子num=4,根据1的式子计算得出V=4,现在要插入一条新纪录,id=234;现在来计算它对应的N值,代入这里给的式子N=234&(4-1)=2;

3、当N>=num时,设置V=Ceiling(V/2),设置N=N&(V-1),由于id=234这条记录,N=2<4所以可以判断它在第三个分区。我们通过执行计划可以看到他的确是被分配到p2分区

这里要注意,分区从p0开始的,就像取模


image.png

KEY分区:
和HASH分区类似,只是HASH分区允许使用用户自定义表达式,而KEY分区不允许使用用户自定义表达式,需要使用MySQL服务器提供的HASH函数,同时HASH分区只支持整数分区,而KEY分区支持使用除了BLOB,TEXT之外其他类型列作分区键。

与HASH分区不同,创建key分区时候可以不指定分区键,默认会选择主键作为分区键,在没有主键情况下会选择非空唯一键作分区键,下面例子便是使用id作为分区键(虽然没有明确指出)

CREATE TABLE k1 (
    id INT NOT NULL,
    name VARCHAR(20),
    UNIQUE KEY (id)
)
PARTITION BY KEY()
PARTITIONS 2;

另外一点,在KEY分区使用LINEAR关键字会与LINEAR HASH有同样效果。

查看文档之后补充一个文档的知识点:对NULL值的处理

MySQL不禁止在分区键值上使用NULL,一般情况下都会把它当成0或者最小值处理。

RANGE分区处理NULL值:

上面我们已经创建了使用range分区的表test1,现在往其中插入null值:

通过执行计划可以发现是被当做最小值处理,所以写入到最小p1分区中(我的表定义p1分区存储最小数据)。
LIST分区处理NULL值:
当我们插入一条包含null值时候,会报如下错误:


image.png

当我们修改分区增加上null定义之后就可以写入。

HASH分区处理NULL:

还是一样对上述所建hash分区的表employees使用执行计划,可以看出在hash分区里把它当做零看待。


image.png

本文链接:https://blog.csdn.net/jiang7701037/article/details/81839899

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 概述 之前,看到分区,我捏个去,好高大上哟。昨天终于知道了分区是个啥玩意,也不过如此,今天总结一下,好记性不如烂笔...
    林湾村龙猫阅读 1,636评论 0 12
  • 分区: 分区的功能不是在存储引擎层实现的。因此不只是InnoDB才支持分区。MyISAM、NDB都支持分区操作。 ...
    4ea0af17fd67阅读 1,763评论 0 0
  • mysql分区 Mysql支持水平分区,并不支持垂直分区;水平分区:指将同一表中不同行的记录分配到不同的物理文件中...
    Gundy_阅读 892评论 0 2
  • 分区是指根据一定的规则,数据库把一个表分解成多个更小的,更容易管理的部分。就访问数据库的应用而言,逻辑上只有一个表...
    微日月阅读 1,493评论 0 7
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,257评论 0 9