MySQL 分区

1.分区

  • InnoDB,MyISAM,NDB引擎都支持分区。
  • mysql5.1开始支持分区。
  • 分区可以提高某些SQL的速度。
  1. 分区:就是把一张表或者索引的数据分成N个区块,在逻辑上看最终只是一张表,但底层是由N个物理区块组成的。
  2. 分表:分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,逻辑上成了多个表,读取数据按表名访问。这些子表可以分布在同一块磁盘上,也可以在不同的机器上。
  3. 分库:多个数据库。

2.MySQL支持分区

  • 水平分区:同一表中不同行的记录分配到不同物理文件中。
  • 垂直分区:同一表中不同列的记录分配到不同物理文件中。
  • MySQL支持水平分区,不支持垂直分区。

3.查看分区命令

  • 使用命令查看是否启用了分区 SHOW VARIABLES LIKE '%partition%';
  • 或者 SHOW PLUGINS;

4.分区类型

  • 无论何种分区,如果表中存在主键或者唯一索引时,分区列必须是唯一索引的一个组成部分。

4.1 RANGE

  • 基于一个给定连续区间范围,把数据分配到不同的分区。
  • 主要用于日期列的分区。
    CREATE TABLE t(
    id INT

    )ENGINE=INNDBPARTITION

    BY RANGE (id)(
    PARTITION p0 VALUES LESS THAN (10),
    PARTITION p1 VALUES LESS THAN (20)
    );

    使用id进行分区, LESS THAN小于10不包括10。 

  1. 如果放入的值不在分区内,则会抛出异常,如放入 id= 30;
  2. 除了限定最小值外,对于大于还可以限定一个  PARTITION p2 VALUES LESS THAN MAXVALUE, 范围之外的值都会放入p2,相当于20到无穷大。
  3. 分区时除了按列还可以使用分区函数,如 BY RANGE YEAR(date) *100 ,他会将查询条件如WHERE date >= '2018-09-12'中的年份值取出×100后放入相应的分区范围。分区范围就得是(201801)
  4. 优化器只会对 YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()这类函数进行优化,会按条件定位到最符合分区查找而不会搜索全部分区。其他函数不会优化。

4.2 LIST 

  • 类似RANGE分区,区别在LIST分区是基于枚举出的值列表分区,是面向离散的值,RANGE是基于给定的连续区间范围分区。
    mysql> CREATE TABLE t ( 
    -> a INT, 
    -> b INT)ENGINE=INNODB 
    -> PARTITION BY LIST(b)( 
    -> PARTITION p0 VALUES IN (1,3,5,7,9), 
    -> PARTITION p1 VALUES IN (0,2,4,6,8)
     -> );
  • 只需给出具体值,不需要顺序。
  • 如果插入的一条数据中某个值不在分区范围那么不同引擎会有不同操作。如(1,4),(10,8)
    1. MyISAM 会将(1,4)插入,(10,8)无法插入。
    2. InnoDB 不会插入任何数据,它视为一个事务失败了。

4.3 HASH

  • 根据MySQL提供的哈希函数来分区。
  1. 不用指定列值存放在哪个分区,分区由MySQL自动生成。
    CREATE TABLE t_hash (
    a INT, 
    b DATETIME)ENGINE=InnoDB
    PARTITION BY HASH (YEAR(b))
    PARTITIONS 4;

     PARTITION BY HASH(expr),其中“expr”是返回一个整数的表达式。

  2. PARTITION BY HASH (YEAR(b)),PARTITION num ; 生成的值会与num取余所以 分区数不会超过num,num可以指定分区数量。
  3. num 不写默认为1。
  4. 选择使点均匀分布的expe很重要,像YEAR 这样的函数值本来就是离散的,所以求余后分布并不均匀
  • 线性HASH分区
    • LINEAR HASH分区,它使用一个更加复杂的算法来确定新行插入到已经分区的表中的位置。它的语法和HASH分区的语法相似,只是将关键字HASH改为LINEAR HASH。
      CREATE TABLE t_linear_hash( 
       a INT, 
       b DATETIME)ENGINE=InnoDB
      PARTITION BY LINEAR HASH (YEAR(b))
      PARTITIONS 4;
    1. 取大于分区数量4的下一个2的幂值V, V=POWER(2,CEILING(LOG(2,num)))=4。 •所在分区N=YEAR('2010-04-01')&(V-1)=2。
    2. LINEAR HASH分区的优点在于增加、删除、合并和拆分分区将变得更加快捷,这有利于处理含有大量数据的表。LINEARHASH分区的缺点在于,与使用HASH分区得到的数据分布相比,各个分区间数据的分布可能不大均衡。

4.4 KEY

  • KEY分区和HASH分区相似,不同之处在于HASH分区通过用户定义的函数进行分区,KEY分区使用MySQL数据库提供的函数进行分区。
  • NDB Cluster引擎使用MD5函数来分区,对于其他存储引擎,MySQL数据库使用其内部的散列函数来分区,这些函数基于与PASSWORD()一样的运算法则
  • 关键字LINEAR在KEY分区中使用和在HASH分区中使用具有同样的作用。
    mysql> CREATE TABLE t_key (   
    -> a INT,    
    -> b DATETIME)ENGINE=InnoDB    
    -> PARTITION BY (LINEAR) KEY (b)    
    -> PARTITIONS 4;

4.5COLUMNS

  • 为了解决RANGE、LIST、HASH和KEY这四种分区中,分区的条件必须是整型(integer)的问题
  • 之前如果不是整型,那么需要通过函数将其转化为整型,如YEAR()、TO_DAYS()、MONTH()等函数
  • 但columns 分区不支持 表达式分区。(它的存在就是为了解决使用表达式分区的情况)
  1. 对于日期不用使用函数就可自动分辨大小,选择合适的分区
  2. 也可枚举各种字符,就和LIST分区一样。
  3. 可以进行多列分区,它的匹配是基于数组比较的,先比较第一列,如果小于该范围则不在比较之后的列,直接放入对应的分区,如果相等则再比较第二列。
    CREATE TABLE rcx (  
    a INT,  
    b INT,  
    c CHAR(3),  
    d INT)Engine=InnoDBPARTITION 
    BY RANGE COLUMNS(a,d,c) (
    PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
    PARTITION p1 VALUES LESS THAN (10,20,'mmmm'),
    PARTITION p2 VALUES LESS THAN (15,30,'sss'),
    PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE));

    也可使用MAXVALUE

5.子分区(复合分区)

  • 子分区(subpartitioning)是在分区的基础上再进行分区,有时也称这种分区为复合分区(composite partitioning)。MySQL数据库允许在RANGE和LIST的分区上再进行HASH或KEY的子分区
    mysql> CREATE TABLE ts (
    a INT, 
    b DATE)engine=innodb    
    -> PARTITION BY RANGE( YEAR(b) )    
    -> SUBPARTITION BY HASH( TO_DAYS(b) )    
    -> SUBPARTITIONS 2 (    
    -> PARTITION p0 VALUES LESS THAN (1990),    
    -> PARTITION p1 VALUES LESS THAN (2000),    
    -> PARTITION p2 VALUES LESS THAN MAXVALUE    
    -> );

6.分区处理null

  1. RANGE 当做最小值。
  2. LIST 必须枚举出来,否则报错。
  3. HASH和KEY都是0值。

8.分区和性能

  1. 对于在线事务处理(OLTP)的应用,电子商务,网络游戏,往往查询时获得的数据量不会太大,使用索引返回很快,对于一张大表B+树2-3次就可以完成操作,分区太细会增加IO次数。
  2. 对于在线分析(OLAP)的应用,如数据仓库,往往要搜寻大量的数据,分区之后可以按条件查找指定分区,这样可以减少IO次数。

9.表与分区交换数据

  • MySQL 5.6开始支持ALTER TABLE……EXCHANGE PAR-TITION语法。该语句允许分区或子分区中的数据与另一个非分区的表中数据进行交换。
  • 如果非分区表的数据为空,那么相当于将分区中的数据移动到非分区表中。
  • 若分区表的数据为空,则相当于将外部表中的数据导入分区中。
  • 要使用ALTER TABLE……EXCHANGE PARTITION语句,必须满足下面的条件:  
  1. 要交换的表须与分区表有相同的表结构,但是表不能含有分区。  
  2. 非分区表中的数据必须在交换的分区内定义。   
  3. 被交换的表中不能含有外键,或者其他表中不能含有对该表的外键引用。  
  4. 用户除了需要ALTER、INSERT和CREATE权限外,还需要DROP的权限。   
  5. 此外,有两个小的细节需要注意:
    1. 使用该语句时,不会触发交换表和被交换表上的触发器。   
    2. AUTO_INCREMENT列将被重置。

参考书籍

  • 《MySQL技术内幕:InnoDB存储引擎》-姜承尧
原文地址:https://www.cnblogs.com/mibloom/p/9142013.html