(3) MySQL分区表使用方法

1. 确认MySQL服务器是否支持分区表

命令:mysql

show plugins;

2. MySQL分区表的特色

  • 在逻辑上为一个表,在物理上存储在多个文件中

HASH分区(HASH)

HASH分区的特色

  • 根据MOD(分区键,分区数)的值把数据行存储到表的不一样分区中
  • 数据能够平均的分布在各个分区中
  • HASH分区的键值必须是一个INT类型的值,或是经过函数能够转为INT类型

如何创建HASH分区表

以INT类型字段 customer_id为分区键

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陆用户ID',
  `login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '用户登陆时间',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陆IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陆类型:0未成功 1成功'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户登陆日志表'

PARTITION BY HASH(customer_id)  PARTITIONS 4;

以非INT类型字段 login_time 为分区键(须要先转换成INT类型)

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陆用户ID',
  `login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '用户登陆时间',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陆IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陆类型:0未成功 1成功'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户登陆日志表'

PARTITION BY HASH(UNIX_TIMESTAMP(login_time))  PARTITIONS 4;

customer_login_log 表若是不分区,在物理磁盘上文件为sql

customer_login_log.frm    # 存储表原数据信息
customer_login_log.ibd    # Innodb数据文件

若是按上面的建HASH分区表,则有五个文件数据库

customer_login_log.frm    
customer_login_log#P#p0.ibd
customer_login_log#P#p1.ibd
customer_login_log#P#p2.ibd
customer_login_log#P#p3.ibd

演示

使用起来和不分区是同样的,看起来只有一个数据库,其实有多个分区文件,好比咱们要插入一条数据,不须要指定分区,MySQL会自动帮咱们处理服务器

查询函数

范围分区(RANGE)

RANGE分区特色

  • 根据分区键值的范围把数据行存储到表的不一样分区中
  • 多个分区的范围要连续,可是不能重叠
  • 默认状况下使用VALUES LESS THAN属性,即每一个分区不包括指定的那个值

如何创建RANGE分区

若是没有定义p3分区,当插入的customer_id大于29999时会报错,定义了则超过的数据都存入p3中优化

RANGE分区的适用场景

  • 分区键为日期或是时间类型 (可使得各个分区表的数据比较均衡,若是按上面的例子中以整型id为分区键,假如活跃用户集中在10000-19999之间,则p1中的数据量就会比其余分区的数据量大不少,这就失去了分区的意义;并且按时间类型分区,若是要按时间顺序进行数据的归档,则只须要对某一个分区进行归档就能够了)
  • 全部查询中都包括分区键(避免跨分区查询)
  • 按期按分区范围清理历史数据

LIST分区

LIST分区的特色

  • 按分区键取值的列表进行分区
  • 同范围分区同样,各分区的列表值不能重复
  • 每一行数据必须能找到对应的分区列表,不然数据插入失败

如何创建LIST分区

若是插入一条login_type为10的数据行,则会报错插件

3. 如何为登陆日志表(customer_login_log)分区

业务场景

  • 用户每次登陆都会记录customer_login_log日志
  • 用户登陆日志保存一年,1年后能够删除或者归档

登陆日志表的分区类型及分区键

  • 使用RANGE分区
  • 以login_time为分区键

分区后的用户登陆日志表

按年份分区存储,因此用YEAR函数进行了转化3d

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陆用户ID',
  `login_time` DATETIME NOT NULL COMMENT '用户登陆时间',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陆IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陆类型:0未成功 1成功'
) ENGINE=InnoDB 
PARTITION BY RANGE (YEAR(login_time))(
PARTITION p0 VALUES LESS THAN (2017),
PARTITION p1 VALUES LESS THAN (2018),
PARTITION p2 VALUES LESS THAN (2019)
)

插入并查询数据日志

查询指定表中的分区数据状况

SELECT table_name,partition_name,partition_description,table_rows FROM
information_schema.`PARTITIONS`  WHERE table_name = 'customer_login_log';

再插入2条18年的日志,会存入p2表中code

以前说过创建分区表时,最好创建一个MAXVALUE的分区,这里之因此没有创建,是为了数据维护的方便,若是咱们创建了MAXVALUE分区,很容易忽视一个问题,当咱们2019年有的数据插入时,会自动存入那个MAXVALUE分区中,以后在作数据维护时会不方便,因此没有创建MAXVALUE分区
而是经过计划任务的方式,在每一年年末的时候增长这个分区,好比咱们如今在2018年年末,咱们须要在日志表中为2019年创建日志分区,不然2019年的日志都会插入失败

咱们能够经过下面语句

增长分区

ALTER TABLE customer_login_log ADD PARTITION (PARTITION p3 VALUES LESS THAN(2020))

增长分区,并插入数据

删除分区

假如咱们如今要删除2016年到2017年间一年的数据,由于咱们已经作了分区,因此只须要经过一条语句,删除p0分区便可

ALTER TABLE customer_login_log DROP PARTITION p0;

能够发现p0分区已被删除,且2016年的日志所有被清除了

归档分区历史数据

咱们可能有另外一种需求对数据进行归档

Mysql版本>=5.7,归档分区历史数据很是方便,提供了一个交换分区的方法

分区数据归档迁移条件:

  1. MySQL>=5.7
  2. 结构相同
  3. 归档到的数据表必定要是非分区表
  4. 非临时表;不能有外键约束
  5. 归档引擎要是:archive

建表并交换分区

CREATE TABLE `arch_customer_login_log` (
  `customer_id` INT unsigned NOT NULL COMMENT '登陆用户ID',
  `login_time` DATETIME NOT NULL COMMENT '用户登陆时间',
  `login_ip` INT unsigned NOT NULL COMMENT '登陆IP',
  `login_type` TINYINT NOT NULL COMMENT '登陆类型:0未成功 1成功'
) ENGINE=InnoDB ;

ALTER TABLE customer_login_log 
    exchange  PARTITION p1 WITH TABLE arch_customer_login_log;

能够发现,原customer_login_log表中的2017年的数据(p1分区中的数据)已转移到了arch_customer_login_log表中,可是p1分区未删除,只是数据转移了,因此咱们还须要执行DROP命令删除分区,以避免有数据插入其中

将归档数据的存储引擎改成归档引擎

最后咱们将归档数据的存储引擎改成归档引擎,命令为

ALTER TABLE customer_login_log  ENGINE=ARCHIVE;

使用归档引擎的好处是:它比Innodb所占用的空间更少,可是归档引擎只能进行查询操做,不能进行写操做

4. 使用分区表的主要事项

  • 结合业务场景选择分区键,避免跨分区查询
  • 对分区表进行查询最好在WHERE从句中包含分区键
  • 具备主键或惟一索引的表,主键或惟一索引必须是分区键的一部分(这也是为何咱们上面分区时去掉了主键登陆日志id(login_id)的缘由,否则就没法按照上面的按年份进行分区,因此分区表其实更适合在MyISAM引擎中)

关于MyISAM和Innodb的索引区别

1.关于自动增加

myisam引擎的自动增加列必须是索引,若是是组合索引,自动增加能够不是第一列,他能够根据前面几列进行排序后递增。

innodb引擎的自动增加咧必须是索引,若是是组合索引也必须是组合索引的第一列。

2.关于主键

myisam容许没有任何索引和主键的表存在,

myisam的索引都是保存行的地址。

innodb引擎若是没有设定主键或者非空惟一索引,就会自动生成一个6字节的主键(用户不可见)

innodb的数据是主索引的一部分,附加索引保存的是主索引的值。

3.关于count()函数

myisam保存有表的总行数,若是select count(*) from table;会直接取出出该值

innodb没有保存表的总行数,若是使用select count(*) from table;就会遍历整个表,消耗至关大,可是在加了wehre 条件后,myisam和innodb处理的方式都同样。

4.全文索引

myisam支持 FULLTEXT类型的全文索引

innodb不支持FULLTEXT类型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。(sphinx 是一个开源软件,提供多种语言的API接口,能够优化mysql的各类查询)

5.delete from table

使用这条命令时,innodb不会重新创建表,而是一条一条的删除数据,在innodb上若是要清空保存有大量数据的表,最 好不要使用这个命令。(推荐使用truncate table,不过须要用户有drop此表的权限)

6.索引保存位置

myisam的索引以表名+.MYI文件分别保存。

innodb的索引和数据一块儿保存在表空间里。

相关文章
相关标签/搜索