资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

mysql表怎么分区 mysql的表分区

十、MySQL表分区

  表分区是将⼀个表的数据按照⼀定的规则⽔平划分为不同的逻辑块,并分别进⾏物理存储,这个规则就叫做分区函数,可以有不同的分区规则。5.7可以通过show plugins语句查看当前MySQL是否⽀持表分区功能。

铁西网站制作公司哪家好,找创新互联!从网页设计、网站建设、微信开发、APP开发、自适应网站建设等网站项目制作,到程序开发,运营维护。创新互联于2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联。

  但当表中含有主键或唯⼀键时,则每个被⽤作 分区函数的字段必须是表中唯⼀键和主键的全部或⼀部分 ,否则就⽆法创建分区表。⽐如下⾯的表由于唯⼀键和主键没有相同的字段,所以⽆法创建表分区

上述例⼦中删除唯⼀键,确保主键中的字段包含分区函数中的所有字段,创建成功

或者将主键扩展为包含ref字段

表分区的主要优势在于:

  可以允许在⼀个表⾥存储更多的数据,突破磁盘限制或者⽂件系统限制

  对于从表⾥将过期或历史的数据移除在表分区很容易实现,只要将对应的分区移除即可

  对某些查询和修改语句来说,可以 ⾃动 将数据范围缩⼩到⼀个或⼏个表分区上,优化语句执⾏效率。⽽且可以通过 显示指定表分区 来执⾏语句,⽐如 SELECT * FROM t PARTITION (p0,p1) WHERE c 5

表分区类型分为:

范围表分区,按照⼀定的范围值来确定每个分区包含的数据,分区函数使⽤的字段必须只能是 整数类型,分区的定义范围必须是连续的,且不能有重叠部分,通过使⽤VALUES LESS THAN来定义分区范围,表分区的范围定义是从⼩到⼤定义的

⽐如:

  Store_id6的数据被放在p0分区⾥,6=store_id10之间的数据被放在p1分区⾥,以此类推,当新插⼊的数据为(72, ‘Mitchell’, ‘Wilson’, ‘1998-06-25’, NULL, 13) 时,则新数据被插⼊到p2分区⾥,但当插⼊的数据的store_id为21时,由于没有分区去容纳此数据,所以会报错,我们需要修改⼀下表的定义

报错:

修改表的定义:

   MAXVALUE关键词的作⽤是表示可能的最⼤值,所以任何store_id=16的数据都会被写⼊到p3分区⾥。分区函数中也可以使⽤表达式 ,⽐如:

   对timestamp字段类型可以使⽤的表达式⽬前仅有unix_timestamp ,其他的表达式都不允许

列表表分区,按照⼀个⼀个确定的值来确定每个分区包含的数据,通过PARTITION BY LIST(expr)分区函数表达式必须返回整数,取值范围通过VALUES IN (value_list)定义

对List表分区来说,没有MAXVALUE特殊值,所有的可能取值都需要再VALUES IN中包含,如果有未定义的取值则会报错

同样,当有主键或者唯⼀键存在的情况下,分区函数字段需要包含在主键或唯⼀键中

对range和list表分区来说,分区函数可以包含多个字段,分区多字段函数(column partition) 所涉及的字段类型可以包括:

范围多字段分区函数与普通的范围分区函数的区别在于:

a) 字段类型多样化

b) 范围多字段分区函数 不⽀持表达式,只能⽤字段名

c) 范围多字段分区函数⽀持⼀个或多个字段

再⽐如创建如下的表分区:

对多列对⽐来说:

当然只要保证取值范围是增⻓的,表分区就能创建成功,⽐如:

但如果 取值范围不是增⻓的,就会返回错误 :

对其他数据类型的⽀持:

list列表多字段表分区,例如:你有一个在12个城市客户的业务, 为了销售和市场的目的, 你的组织每3个城市划分为一个区域针对LIST COLUMNS分区, 你可以基于城市的名称创建一个客户数据表并声明4个分区当你的客户在对应的这个区域:

使用日期分区

但是这种情况在日期增长到非常大的时候是很复杂的, 所以这种还是使用RANGE 分区方式比较好

  按照⼀个⾃定义的函数返回值来确定每个分区包含的数据,这个 ⾃定义函数也可以仅仅是⼀个字段名字

  通过PARTITION BY HASH (expr)⼦句来表达哈希表分区,其中的 expr表达式必须返回⼀个整数,基于分区个数的取模(%)运算。根据余数插⼊到指定的分区

  对哈希表分区来说只需要定义分区的个数,其他的事情由内部完成

如果没有写明PARTITIONS字段,则默认为1,表达式可以是整数类型字段,也可以是⼀个函数,⽐如

⽐如: CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY HASH( YEAR(col3) ) PARTITIONS 4;

如果插⼊⼀条数据对应的col3为‘2005-09-15’时,则插⼊数据的分区计算⽅法为:

  与哈希表分区类似,只不过哈希表分区依赖于⾃定义的函数,⽽key表分区的哈希算法是依赖MySQL本身, CREATE TABLE ... PARTITION BY KEY () 创建key表分区, 括号⾥⾯可以包含0个或者多个字段,所引⽤的字段必须是主键或者主键的⼀部分 ,如果括号⾥⾯没有字段,则代表使⽤主键

如果表中没有主键但有唯⼀键,则使⽤唯⼀键,但 唯⼀键字段必须定义为not null ,否则报错

所引⽤的字段未必必须是整数类型,其他的类型也可以使⽤,⽐如:

⼦表分区,是在表分区的基础上再创建表分区的概念, 每个表分区下的⼦表分区个数必须⼀致 ,⽐如:

ts表拥有三个范围分区,同时每个分区都各⾃有两个⼦分区,所以总共有6个分区

⼦表分区必须是范围/列表分区+哈希/key⼦表分区的组合

⼦表分区也可以显示的指定⼦表分区的名字,⽐如:

不同的表分区对NULL值的处理⽅式不同

对范围表分区来说,如果插⼊的是NULL值,则将数据放到最⼩的分区表⾥

对list表分区来说,⽀持NULL值的唯⼀情况就是某个分区的允许值中包含NULL

对哈希表分区和Key表分区来说,NULL值会被当成0值对待

通过alter table命令可以执⾏增加,删除,重新定义,合并或者拆分表分区的管理动作

对范围表分区和列表表分区来说,删除⼀个表分区命令如下:

删除表分区的动作不光会把分区删掉,也会把表分区⾥原来的数据给删除掉

在原分区上增加⼀个表分区可以通过alter table … add partition语句来完成

但对范围表分区来说,增加的表分区必须在尾部增加,在头部或者在中间增加都会失败:

为解决这个问题,可以使⽤ REORGANIZE 命令:

对列表表分区来说,只要新增加的分区对应的值在之前的表分区中没有出现过,就可以通过alter table… add partition来增加

当然, 也可以通过REORGANIZE命令将之前的多个分区合并成⼀个或⼏个分区,但要保持分区值⼀致:

更复杂的⽐如将多个分区重组成多个分区:

Mysql分区表Partition

一、背景

话说风和日丽的一天,为提高随着业务增长的大表(3510449行吧)的访问效率,于是决定对表分区,记录如下。

二、实操

结合业务,若干条记录会集中在一个日期,查询时也往往只查询一个日期内的数据,于是选取分区字段为时间。

创建分区 比如

CREATE TABLE message_all (

id int(10) NOT NULL AUTO_INCREMENT,

......

createtime datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'

PRIMARY KEY ( id , createtime )

) ENGINE=InnoDB DEFAULT CHARSET=utf8

PARTITION BY RANGE (YEAR(createtime))

(PARTITION p2015 VALUES LESS THAN (2016) ENGINE = InnoDB,

PARTITION p2016 VALUES LESS THAN (2017) ENGINE = InnoDB,

PARTITION p2017 VALUES LESS THAN (2018) ENGINE = InnoDB,

PARTITION p2018 VALUES LESS THAN MAXVALUE ENGINE = InnoDB)

不过我们表已经有了当然不能这么建,除非你想导一次数据。

如下操作 :

1、

ALTER TABLE message_all PARTITION BY RANGE (to_days(createtime))

(

PARTITION p2015 VALUES LESS THAN (to_days('2016-01-01')),

PARTITION p2016 VALUES LESS THAN (to_days('2017-01-01')),

PARTITION p2017 VALUES LESS THAN (to_days('2018-01-01')),

PARTITION p2018 VALUES LESS THAN MAXVALUE

);

或者

2、ALTER TABLE message_all PARTITION BY RANGE (YEAR(createtime))

(

PARTITION p2015 VALUES LESS THAN (YEAR('2016-01-01'))

);

然后追加。

ALTER TABLE message_all ADD PARTITION

(

PARTITION p2016 VALUES LESS THAN (YEAR('2017-01-01')),

PARTITION p2017 VALUES LESS THAN (YEAR('2018-01-01')),

PARTITION p2018 VALUES LESS THAN MAXVALUE

);

这里会有几种错误情况:

1、ALTER TABLE message_all PARTITION BY RANGE (to_days(createtime)) ;

[Err] 1492 - For RANGE partitions each partition must be defined

解释:必须指定至少一个分区。

2、[Err] 1492 - A PRIMARY KEY must include all columns in the table's partitioning function

解释:分区字段必须是主键之一。

3、[Err] 1492 - Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed

解释:分区字段为timestamp,换成datetime。

4、[Err] 1526 - Table has no partition for value xxxx

解释:用追加方式第一次必须覆盖目前所有数据。

总结:

1、创建时必须指定至少一个分区。

2、key必须为主键之一。

3、RANGE处必须为INT型,时间字段用函数转——YEAR()、YEARWEEK()、TO_DAYS()。

4、THAN处必须为INT型,时间字段用函数转——TO_DAYS、TO_SECONDS()、UNIX_TIMESTAMP()。

5、它就是以两个INT比大小划分的文件。

6、所有ENGINE必须一样。

7、范围分区添加只能在最大值后面追加。

8、分区是有上限的貌似1024个。

用到的其他操作

1、删除分区(直接扔掉分区文件,数据也没了)

ALTER TABLE message_all DROP PARTITION p2016;

2、清空分区数据

ALTER TABLE message_all TRUNCATE PARTITION p2017;

3、重定义(可实现:分区拆分、合并、重命名)

ALTER TABLE message_all REORGANIZE PARTITION p201601,p201602,p201603,p201604 INTO

(

PARTITION p2016012 VALUES less than(TO_DAYS('2016-03-01')),

PARTITION p2016034 VALUES less than(TO_DAYS('2016-05-01'))

);

检查/查看你的分区

1、SHOW TABLE STATUS LIKE 'message_all';

2、SELECT * FROM information_schema.partitions WHERE table_name='message_all';

3、SHOW CREATE TABLE message_all;

4、EXPLAIN SELECT COUNT(1) FROM message_all WHERE createtime= '2016-01-01' AND createtime '2016-12-30';如果用到了分区partitions里会有显示。

5、指定分区查

SELECT COUNT(1) FROM message_all PARTITION (p2016) 表别名 WHERE ......;

到这里就结束啦,土豆白。

一些概念

水平分区Partition有以下几种模式

MySQL-分区表

对底层表的封装,意味着索引也是按照分区的子表定义的,而没有全局索引。(所以即使有唯一性索引,在不同子表中可能会有重复数据)

单表数据量超大时索引失效

将单表分区成数个区域,通过分区函数,可以快速地定位到数据的区域。而且相比于索引,分区不需要额外的数据结构记录每个分区的数据,代价更低。只需要一个简单的表达式就可以指向正确的分区

可以只是用简单的分区方式存放表,不要任何索引,只要将查询定位到需要的大致数据位置,通过where条件,将需要的数据限制在少数分区中,则效率是很高的。WARNNING:查询需要扫描的分区个数限制在一个很小的数量。

如果数据有明显的“热点”,可以将热点数据单独放在一个分区,让这个分区的数据能够有机会都缓存在内存中。

如果分区表达式的值可以是NULL:第一个分区会使一个特殊分区。以partition by range year(order_date)为例,所有在order_date列为NULL或者非法值的数据都会被放到第一个分区。那么所有的查询在定位分区后都会增加扫描第一个分区。而且如果第一个分区很大的时候,查询的成本会被这个“拖油瓶”分区无情的增加。

创建一个无用的第一分区可以解决这个问题,partition p_nulls values less than (0);

对于分区列和索引列不匹配的查询,虽然查询能够使用索引,但是无法通过分区定位到目标数据的分区(也就是数据分布相对更加分散),需要遍历每个分区内的索引,除非查询中的条件同时也包含分区条件。所以期望分区条件范围被热门查询索引所包含。

对于 范围分区 技术,需要适当限制分区的数量,否则对于大量数据批量导入的场景,选择分区的成本过高。对于大多数系统,100个左右的分区是没有问题的。

MySQL分区表简介

我们的业务只存近一段时间的数据,因此有大量表需要清理 历史 数据,目前使用的delete清理数据,存在以下问题。为避免同时支持大量delete,我们的清理任务只在低峰期串行执行,导致任务过多时需要排队,甚至失败的情况;数据清理使用delete语句,表数据量较大时,对数据库造成很大压力;即使我们删除了旧数据,已删除的数据仍占据存储空间,底层数据文件并没有立刻变小,以至于形成数据空洞。

查看MySQL官方文档时,发现了分区表,因此基于官方文档总结一下。

MySQL逻辑上为一个表,物理上存储在多个文件中,这是 MySQL 支持的功能(5.1 开始), 8.0 版本只 InnoDB 和 NDB 支持分区表。

优点:

缺点:

根据分区表键值的范围把数据存储到表的不同分区中,适用于以时间或日期作为分区类型,方便数据清理。

小提示:

1.当插入数据分区不存在时会报错:Table has no partition for value xxx;

2.Range类型分区字段必须是数值,时间类型可用函数转换为数值;

3.分区字段列值可以为null,所有为null的数据将存在最小的分区中;

按分区键取值的列表进行分区,每一行数据须找到对应的分区列表,否则数据插入失败

小提示:

根据指定分区表达式的整数值以及分区数进行数据划分(mod函数)

小提示:

按键分区类似于按哈希分区,只是哈希分区使用用户定义的表达式,用于键分区的哈希函数由 MySQL 服务器提供。NDB 集群为此使用 MD5() ; 对于使用其他存储引擎的表,服务器使用自己的内部哈希函数。

小提示:

子分区(subpartitioning)也称为复合分区(composite partitioning) ,是已分区表中每个分区的进一步划分

小提示:

小提示:

Mysql按时间进行表分区

以下是创建一张测试表TEST并且按照时间CREATE_TIME创建RANGE分区,并使用ID创建hash分区,组成复合分区。

CREATE TABLE TEST (

CREATE_TIME DATETIME DEFAULT NULL, ID BIGINT(15) DEFAULT NULL

) ENGINE=INNODB DEFAULT CHARSET=utf8

PARTITION BY RANGE(TO_DAYS(CREATE_TIME)) PARTITIONS 7 SUBPARTITION BY HASH(ID) SUBPARTITIONS 16

(PARTITION P1710 VALUES LESS THAN (TO_DAYS ('2017-10-01'))

(SUBPARTITION P1710sp0 ,SUBPARTITION P1710sp1 ,

SUBPARTITION P1710sp2 ,SUBPARTITION P1710sp3 ,

SUBPARTITION P1710sp4 ,SUBPARTITION P1710sp5 ,

SUBPARTITION P1710sp6 ,SUBPARTITION P1710sp7 ,

SUBPARTITION P1710sp8 ,SUBPARTITION P1710sp9 ,

SUBPARTITION P1710sp10 ,SUBPARTITION P1710sp11 ,

SUBPARTITION P1710sp12 ,SUBPARTITION P1710sp13 ,

SUBPARTITION P1710sp14 ,SUBPARTITION P1710sp15 ),

PARTITION P1711 VALUES LESS THAN (TO_DAYS ('2017-11-01'))

(SUBPARTITION P1711sp0 ,SUBPARTITION P1711sp1 ,

SUBPARTITION P1711sp2 , SUBPARTITION P1711sp3 ,

SUBPARTITION P1711sp4 , SUBPARTITION P1711sp5 ,

SUBPARTITION P1711sp6 , SUBPARTITION P1711sp7 ,

SUBPARTITION P1711sp8 , SUBPARTITION P1711sp9 ,

SUBPARTITION P1711sp10 , SUBPARTITION P1711sp11 ,

SUBPARTITION P1711sp12 , SUBPARTITION P1711sp13 ,

SUBPARTITION P1711sp14 , SUBPARTITION P1711sp15 ),


文章名称:mysql表怎么分区 mysql的表分区
转载来源:http://cdkjz.cn/article/heppjp.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220