MySQL表分区

分区表是什么

就是把很大数据量的数据拆分存在不同的数据文件中,来达到提升查询效率的做法。每个分区表都有一个句柄对象,mysql通过对句柄对象的管理使得多个底层的分区表看上去就是一个逻辑表

常见使用场景

  • 当数据量很大(过T)时,肯定不能把数据再如到内存中,这样查询一个或一定范围的item是很耗时。另外一般这情况下,历史数据或不常访问的数据占很大部分,最新或热点数据占的比例不是很大。这时可以根据有些条件进行表分区。
  • 分区表的更易管理,比如删除过去某一时间的历史数据,直接执行truncate,或者狠点drop整个分区,这比detele删除效率更高
  • 当数据量很大,或者将来很大的,但单块磁盘的容量不够,或者想提升IO效率的时候,可以把没分区中的子分区挂载到不同的磁盘上。
  • 使用分区表可避免某些特殊的瓶颈,例如Innodb的单个索引的互斥访问..
  • 单个分区表的备份很恢复会更有效率,在某些场景下

总结:可伸缩性,可管理性,提高数据库查询效率

各个分区说明

range分区:一般按照数据的范围来分区,但是是连续的,比如按照年龄来分

mysql> create table t4 (id int, name varchar(20),age int(3))

-> partition by range(age)                    #确定按照age字段分区

-> (

-> partition p01 values less than (20),        

-> partition p02 values less than (30),            #age在[20,30)

-> partition p03 values less than (maxvalue)        #age在 [30,maxvalue

-> );

list分区:将一些离散的值放在一个分区。如将商品id为1,2,3放在一个分区。注意在5.1中只能使用匹配整数,5.5+可以使用字符串和日期作为分区定义列

mysql > create table t5 (id int, type int(3), name varchar(20), price float(10,2))

-> partition by list (type)

-> (

-> partition p01 values in (1,2,3),

-> partition p02 values in (4,5,6),

-> partition p03 values in (7,8,9,0)

-> );

hash分区:基于列值,或者表达式进行hash算法。在MySQL cluster 中分区是自动的,默认是和ndb_node数量相同的。

mysql> create table t6 (id int, type int(3), name varchar(20), price float(10,2))

-> partition by hash (type)

-> partitions 4;                    #分区个数

Linear hash线性hash:使用线性2次幂运算法则,优点在于增加、删除、合并和拆分分区更快捷,利于处理含有很大数据的表(1T)。但它的算法不很均匀,有可能导致hotspot nodes的问题

mysql> create table t7 (id int, type int(3), name varchar(20), price float(10,2))

-> partition by linear hash (type)    #只是比hash分区多个linear关键字

-> partitions 4;                    #分区个数

key分区:基本和hash相同,不常使用

mysql> create table t7 (id int, type int(3), name varchar(20), price float(10,2))

-> partition by linear key (type)    

-> partitions 4;                    #分区个数

多列分区:在5.5+之后支持。columns关键字允许字符串和日期作为分区定义列,分区可以根据多列的值,匹配数据优先级从左至右。

mysql> create table t8 (id int, type int(3), name varchar(20), price float(10,2), online date)

-> partition by range columns (type,online)

-> (

-> partition p01 values less than (5,'2004-01-01'),

-> partition p02 values less than (5,'2012-01-01'),

-> partition p03 values less than (10,'2016-01-01'),

-> partition p04 values less than (maxvalue,maxvalue)

-> );

子分区:在分区的基础在分区。子分区可以用于特别大的表,在多个磁盘间分配数据和索引,提升IO效率

root@localhost: testx 12:00 > create table t11 (id int, type int(3), name varchar(20), price float(10,2), online date)

-> partition by list (type)

-> subpartition by hash (year(online))

-> (

-> partition p0 values in (1,2,3)

-> (

-> subpartition s0

-> data directory = '/data/sda/data'

-> index directory = '/data/sda/index',

-> subpartition s1

-> data directory = '/data/sdb/data'

-> index directory = '/data/sdb/index'

-> ),

-> partition p1 values in (4,6,5)

-> (

-> subpartition s2

-> data directory = '/data/sdc/data'

-> index directory = '/data/sdc/index',

-> subpartition s3

-> data directory = '/data/sdd/data'

-> index directory = '/data/sdd/index'

-> )

-> );

注意语法:每个分区必须都相同数量的子分区;有一个分区定义子分区其他分区都得定义

分区管理

修改表的分区方式,或者对已存在的表但没有表分区新增表分区

建议在生产环境中尽量不要修改分区,alter会读出存在旧表中的数据,再存入新定义的表中,过程IO将很大,而且全表都会锁住。

alter table t1 partition by hash(type) partitions 3;

range & list分区删除指定的分区

删除分区数据:truncate保留分区结构,只删除分区里面的数据,效率比delete高。drop直接整个删除,包括分区和里面的数据。其中truncate用的很大

alter table t1 drop partition p01;

alter table t1 truncate partition p01;

range分区增加分区表:注意添加的数据范围必须在比当前最大值还大

alter table t1 add partition (partition p2 values less than (2016) );

list分区增加分区:新增的分区中的value不能存在现有的分区values中

alter table t5 add partition (partition p04 values in (10,11));

分区重组:大分区拆分成多个小分区,把小分区综合成大分区

对于range分区,只能重新组织相邻的分区;

拆分:mysql> alter table t1 reorganize partition p03 into (

-> partition p12 values less than (30),

-> partition p13 values less than (maxvalue)

-> );

合并:alter table t4 reorganize partition p12,p13 into ( partition p03 values less than (maxvalue) );

hash和key分区管理

缩减:alter table t6 coalesce partition 2;        # coalesce中文意:合并

增加:alter table t6 add partition partitions 2;    #增加了,不是增加到

分区维护

重建分区:整理分区碎片,先抽取数据,之后重建分区,最后导回

alter table t4 rebuild partition p01,p02;

优化分区:如果从分区中删除了大量的行,或者对text,blob等做了大量的修改,此时需要整理数据文件碎片,相比较rebuild性能消耗小些

alter table t4 optimize partition p01,p02;

检测修复分区

alter table t1 check partition p01,p02;

alter table t1 repair partition p01,p02;

使用分区注意点

  • 当访问超大数据量的情况下,硬件设备也较差时,在检索数据的时候,索引根本不起作用的,查询依旧很慢,这时可以使用分区表。目的就是曾大查询粒度,先确定大范围在确定单条记录。但是分区的数量最好保证在100个分区内,比如在写入大量数据到分区表时,每写入一条数据,都要判断数据的范围来确定到底存在哪里,所以限定分区表数量可以缓解像这样的问题
  • 分区列最好和索引列匹配
  • 如果分片的条件返回的数据为null值的话,那么mysql将会在第一分区检索数据,比如使用year(online_date)作为分片的列,当使用year(123213213)返回就为null值。如果5.5之前的版本,最好建立单独第一分区来存放非法的数据,如果数据都插入正常的话,这个分区就是空的,即使扫描这个表,也会很快完成
  • 管理成本很高,重组分区的原理和alter类似,先创建一个临时的分区,然后将数据复制到其中,最后删除原分区。
  • 另外所有的分区必须使用相同的存储引擎
  • 需要更多的文件描述符

合并表和分区表

  • 合并表可以将多个已经存在的结构相同的整合为同一张逻辑表,数据的插入,只能指定存在某一个表中(last first),但分区表操作比较灵活。
  • 合并表可以单独存在子表,但是分区表是通过mysql内部来从子表检索数据
  • 另外在创建合并表的时候,它不检查兼容性,在后期的使用中可能会有意外的错误

使用合并表注意点

使用between范围查找时,会在各子表查询,不会像分区表先确定范围再到子分区查找。

在合并表做唯一索引或主键时,一旦找到数据,就停止查找。

扫描子分区是按照表定义时表的顺序进行查找的

合并表很容易管理子表,添加时,删除定义再重新定义。

分区表的查询

在使用between范围查找时,查询应根据原来实际的数据类型来作为条件

通过explain partitions select … \G;来确定分区的使用情况。

mysql> explain partitions select * from t5 where type=2\G;

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: t5

partitions: p01            #注意这里只使用p01,如果不加where条件时将检索整个分区

type: ALL

possible_keys: NULL

key: NULL

key_len: NULL

ref: NULL

rows: 2

Extra: Using where

posted @ 2016-01-18 14:07  Rikewang  阅读(320)  评论(0编辑  收藏  举报