Mysql分区表总结

分区表介绍

        分区是指根据一定的规则将一个大表分解成多个更小的部分,这里的规则一般就是利用分区规则将表进行水平切分;逻辑上没有发生变化但实际上表已经被拆分成了多个物理对象,每个分成被划分成了一个独立的对象。相对于没有分区的当个表而言分区的表有很多的优势包括: 并发统计查询、快速归档删除分区数据、分散存储、查询性能更佳。

查看当前数据库是否开启分区

5.7之前的版本使用:show variables like '%partition%';

mysql 5.7使用: SHOW PLUGINS;

分区类型

  • RANGE分区:基于一个给定的连续区间范围,RANGE主要是基于整数的分区,对于非整形的字段需要利用表达式将其转换成整形。
  • LIST分区:是基于列出的枚举值列表进行分区。
  • COLUMNS分区:可以无需通过表达式进行转换直接对非整形字段进行分区,同时COLUMNS分区还支持多个字段组合分区,只有RANGELIST存在COLUMNS分区,COLUMNS是RANGE和LIST分区的升级。
  • HASH分区:基于给定的分区个数,将数据分配到不同的分区,HASH分区只能针对整数进行HASH,对于非整形的字段只能通过表达式将其转换成整数。
  • KEY分区:支持除text和BLOB之外的所有数据类型的分区,key分区可以直接基于字段做分区无需转换成整数。

实际使用案例

Range分区


create table  (
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
partition by range (分区字段) (
  partition <分区名称> values less than (Value),
  partition <分区名称> values less than (Value),
  ...
  partition <分区名称> values less than maxvalue
);

List分区

create table 
( // 字段 ) ENGINE=数据库引擎 DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 partition by LIST (分区字段或者基于该字段的返回的整数值的表达式) ( partition <分区名称> values IN (Value1,Value2, Value3), ... partition <分区名称> values IN (Value4, Value5), );

columns分区


columns分区分为 range columns 和 list columns 两种

支持整数(tinyint到bigint,不支持decimal 和float)、日期(date、datetime)、字符串(char、varchar、binary、varbinary)三类

columns分区支持一个或者多个字段作为分区键,不支持表达式作为分区键,这点区别于range 和 list 分区。

多列排序,先根据a字段排序再根据b字段排序,根据排序结果来分区存放数据

create talbe rc3 (
    a int,
    b int
)
partition by range columns(a, b) (
    partition p01 values less than (0, 10),
    partition p02 values less than (10, 10),
    partition p03 values less than (10, 20),
    partition p04 values less than (10, 35),
    partition p05 values less than (10, maxvalue),
    partition p06 values less than (maxvalue, maxvalue),
);
insert into rc3(a, b) values(1, 10);
select (1, 10) < (10, 10) from dual;
-- 根据结果存放到p02分区上了  1小于10 10等于10  在02规定的范围内
select
    partition_name,
    partition_expression,
    partition_description,
    table_rows
from information_schema.partitions
where table_schema = schema() and table_name = 'rc3';    

HASH分区

分区键应用一个散列函数,以此确定数据应当放在N个分区中的哪个分区

mysql支持两种hash分区:常规hash分区和线性hash分区

常规hash分区使用的是取模算法,对应一个表达式expr是可以计算出它被保存到哪个分区中,N = MOD(expr, num)
线性hash分区使用的是一个线性的2的幂运算法则。
对指定的字段(整型字段)进行哈希,将记录平均的分配到分区中,使得所有分区的数据比较平均。 hash分区只需要指定要分区的字段和要分成几个分区,
expr是一个字段值或者基于某列值云散返回的一个整数,

expr可以是mysql中有效的任何函数或者其它表达式,只要它们返回一个即非常熟也非随机数的整数。num 表示分区数量

-- HASH

create table 
(     // 字段 ) ENGINE=数据库引擎  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 PARTITION BY HASH(expr) PARTITIONS ;

常规hash问题:新增的话 会导致重新计算
        常规hash分区方式看上去挺不错的,通过取模的方式来数据尽可能平均分布在每个分区,让每个分区管理的数据都减少,提高查询效率,可是当我们要增加分区时或者合并分区,问题就来了,假设原来是5个常规hash分区,现在需要增加一个常规分区,原来的取模算法是MOD(expr, 5), 根据余数0~4分布在5个分区中,现在新增一个分区后,取模算法变成MOD(expr, 6),根据余数0~6分区在6个分区中,原来5个分区的数据大部分都需要通过重新计算进行重新分区。

线性hash分区
        常规hash分区在管理上带来了的代价太大,不适合需要灵活变动分区的需求。为了降低分区管理上的代价,mysql提供了线性hash分区,分区函数是一个线性的2的幂的运算法则。同样线性hash分区的记录被存在那个分区也是能被计算出来的。线性hash分区的优点是在分区维护(增加、删除、合并、拆分分区)时,mysql能够处理的更加迅速,缺点是:对比常规hash分区,线性hash各个分区之间数据的分布不太均衡。

-- LINEAR HASH
create table 
(     // 字段 ) ENGINE=数据库引擎  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 PARTITION BY LINEAR HASH(expr) PARTITIONS ;


key分区


        按照key进行分区非常类似于按照hash进行分区 分区的字段可以是非int类型,如字符串、日期等类型,KEY分区使用系统提供的HASH函数进行分区,同Hash分区Key分区也可使用线性分区

partition by key(expr) partitions num;
 
-- 不指定默认首选主键作为分区键,在没有主键的情况下会选择非空唯一键作为分区键
partition by key() partitions num;
 
-- linear key
partition by linear key(expr)
 
create table 
(     // 字段 ) ENGINE=数据库引擎  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 PARTITION BY KEY(分区字段名) PARTITIONS ;

复合分区


是分区表中对每个分区的再次分割,支持对range和list进行父分区,复合分区即可以使用hash分区也可以使用key分区进行子分区。

复合分区适用于保存非常大量的数据记录。

-- 根据年进行分区
-- 再根据天数分区
-- 3个range分区(p0,p1,p2)又被进一步分成2个子分区,实际上整个分区被分成了 3 x 2 = 6个分区
create table ts (
    id int, 
    purchased date
) 
partition by range(year(purchased))
subpartition by hash(to_days(purchased)) subpartitions 2 
(
    partition p0 values less than (1990),
    partition p0 values less than (2000),
    partition p0 values less than maxvalue
);
 
CREATE TABLE IF NOT EXISTS `sub_part` (
  `news_id` int(11) NOT NULL  COMMENT '新闻ID',
  `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新闻内容',
  `u_id`  int(11) NOT NULL DEFAULT 0s COMMENT '来源IP',
  `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '时间'
) ENGINE=INNODB  DEFAULT CHARSET=utf8
PARTITION BY RANGE(YEAR(create_time))
SUBPARTITION BY HASH(TO_DAYS(create_time))
(
PARTITION p0 VALUES LESS THAN (1990) (SUBPARTITION s0, SUBPARTITION s1, SUBPARTITION s2),
PARTITION p1 VALUES LESS THAN (2000) (SUBPARTITION s3, SUBPARTITION s4, SUBPARTITION good),
PARTITION p2 VALUES LESS THAN MAXVALUE (SUBPARTITION tank0, SUBPARTITION tank1, SUBPARTITION tank3)
);

管理分区


        mysql提供了添加、删除、重定义、合并、拆分分区的命令,这些操作都可以通过alter table 命令来实现

-- 删除list或者range分区(同时删除分区对应的数据)
alter table 
drop partition <分区名称>; -- 移除分区 使用remove移除分区是仅仅移除分区的定义,并不会删除数据和drop PARTITION不一样,后者会连同数据一起删除 ALTER TABLE
REMOVE PARTITIONING ;   -- 新增分区 -- range添加新分区 alter table
add partition(partition p4 values less than MAXVALUE);   -- list添加新分区 alter table
add partition(partition p4 values in (25,26,28));   -- hash重新分区 alter table
add partition partitions 4;   -- key重新分区 alter table
add partition partitions 4;   -- 子分区添加新分区,虽然我没有指定子分区,但是系统会给子分区命名的 alter table
add partition(partition p3 values less than MAXVALUE);   -- range重新分区 ALTER TABLE user REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES LESS THAN MAXVALUE);   -- list重新分区 ALTER TABLE
REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES in (1,2,3,4,5));

特别说明

  1. 注意分区名的大小写敏感问题,和关键字问题。
  2. 无论哪种分区类型,要么分区表中没有主键或唯一键,要么主键或唯一键包含在分区列里面,对于存在主键或者唯一键的表不能使用主键或者唯一键之外的字段作为分区字段。
  3. 5.7以前的版本显示分区的执行计划使用:explain PARTITIONS;5.7以后直接执行:explain
  4. 没有强制要求分区列非空,建议分区的列为NOT NULL的列;在RANGE 分区中如果往分区列中插入NULL值会被当作最小的值来处理,在LIST分区中NULL值必须在枚举列表中否则插入失败,在HASH/KEY分区中NULL值会被当作0来处理。
  5. 基于时间类型的字段的转换函数mysql提供了"YEAR(),MONTH(),DAY(),TO_DAYS(),TO_SECONDS(),WEEKDAY(),DAYOFYEAR()"
  6. 拆分合并分区后会导致修改的分区的统计信息失效,没有修改的分区的统计信息还在,不影响新插入的值加入到统计信息;这时需要对表执行Analyze操作.
  7. 针对非整形字段进行RANG\LIST分区建议使用COLUMNS分区。

你可能感兴趣的:(mysql,数据分区,MySQL分区表,数据库)