完全搞懂 MySQL 分区!

GrimMjx
https://www.cnblogs.com/GrimM...

一.InnoDB逻辑存储结构

首先要先介绍一下InnoDB逻辑存储结构和区的概念,它的全部数据都被逻辑地存放在表空间,表空间又由段,区,页组成html

段就是上图的segment区域,常见的段有数据段、索引段、回滚段等,在InnoDB存储引擎中,对段的管理都是由引擎自身所完成的。mysql

区就是上图的extent区域,区是由连续的页组成的空间,不管页的大小怎么变,区的大小默认老是为1MB。为了保证区中的页的连续性,InnoDB存储引擎一次从磁盘申请4-5个区,InnoDB页的大小默认为16kb,即一个区一共有64(1MB/16kb=16)个连续的页。sql

每一个段开始,先用32页(page)大小的碎片页来存放数据,在使用完这些页以后才是64个连续页的申请。这样作的目的是,对于一些小表或者是undo类的段,能够开始申请较小的空间,节约磁盘开销。数据库

页就是上图的page区域,也能够叫块。页是InnoDB磁盘管理的最小单位。默认大小为16KB,能够经过参数innodb_page_size来设置。常见的页类型有:数据页,undo页,系统页,事务数据页,插入缓冲位图页,插入缓冲空闲列表页,未压缩的二进制大对象页,压缩的二进制大对象页等。  segmentfault

二.分区概述

这里讲的分区,此“区”非彼“区”,这里讲的分区的意思是指将同一表中不一样行的记录分配到不一样的物理文件中,几个分区就有几个.idb文件,不是咱们刚刚说的区。函数

MySQL在5.1时添加了对水平分区的支持。分区是将一个表或索引分解成多个更小,更可管理的部分。每一个区都是独立的,能够独立处理,也能够做为一个更大对象的一部分进行处理。这个是MySQL支持的功能,业务代码无需改动。要知道MySQL是面向OLTP的数据,它不像TIDB等其余DB。那么对于分区的使用应该很是当心,若是不清楚如何使用分区可能会对性能产生负面的影响。性能

 MySQL数据库的分区是局部分区索引,一个分区中既存了数据,又放了索引。也就是说,每一个区的汇集索引和非汇集索引都放在各自区的(不一样的物理文件)。目前MySQL数据库还不支持全局分区。
 
  不管哪一种类型的分区,若是表中存在主键或惟一索引时,分区列必须是惟一索引的一个组成部分优化

三.分区类型

目前MySQL支持一下几种类型的分区,RANGE分区,LIST分区,HASH分区,KEY分区。若是表存在主键或者惟一索引时,分区列必须是惟一索引的一个组成部分。实战十有八九都是用RANGE分区spa

RANGE分区

RANGE分区是实战最经常使用的一种分区类型,行数据基于属于一个给定的连续区间的列值被放入分区。可是记住,当插入的数据不在一个分区中定义的值的时候,会抛异常。RANGE分区主要用于日期列的分区,好比交易表啊,销售表啊等。能够根据年月来存放数据。若是你分区走的惟一索引中date类型的数据,那么注意了,优化器只能对YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()这类函数进行优化选择。实战中能够用int类型,那么只用存yyyyMM就行了。也不用关心函数了。3d

CREATE TABLE `m_test_db`.`Order` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `partition_key` INT NOT NULL,
  `amt` DECIMAL(5) NULL,
  PRIMARY KEY (`id`, `partition_key`)) PARTITION BY RANGE(partition_key) PARTITIONS 5( PARTITION part0 VALUES LESS THAN (201901),  PARTITION part1 VALUES LESS THAN (201902),  PARTITION part2 VALUES LESS THAN (201903),  PARTITION part3 VALUES LESS THAN (201904),  PARTITION part4 VALUES LESS THAN (201905)) ;

这时候咱们先插入一些数据

INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('1', '201901', '1000');
INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('2', '201902', '800');
INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('3', '201903', '1200');

如今咱们查询一下,经过EXPLAIN PARTITION命令发现SQL优化器只需搜对应的区,不会搜索全部分区

  若是sql语句有问题,那么会走全部区。会很危险。因此分区表后,select语句必须走分区键

如下3种不是太经常使用,就一笔带过了。

#### LIST分区

LIST分区和RANGE分区很类似,只是分区列的值是离散的,不是连续的。LIST分区使用VALUES IN,由于每一个分区的值是离散的,所以只能定义值

#### HASH分区

  说到哈希,那么目的很明显了,将数据均匀的分布到预先定义的各个分区中,保证每一个分区的数量大体相同。

KEY分区

KEY分区和HASH分区类似,不一样之处在于HASH分区使用用户定义的函数进行分区,KEY分区使用数据库提供的函数进行分区。

四.分区和性能

一项技术,不是用了就必定带来益处。好比显式锁功能比内置锁强大,你没玩好可能致使很很差的状况。分区也是同样,不是启动了分区数据库就会运行的更快,分区可能会给某些sql语句性能提升,可是分区主要用于数据库高可用性的管理。数据库应用分为2类,一类是OLTP(在线事务处理),一类是OLAP(在线分析处理)。对于OLAP应用分区的确能够很好的提升查询性能,由于通常分析都须要返回大量的数据,若是按时间分区,好比一个月用户行为等数据,则只需扫描响应的分区便可。在OLTP应用中,分区更加要当心,一般不会获取一张大表的10%的数据,大部分是经过索引返回几条数据便可。

好比一张表1000w数据量,若是一句select语句走辅助索引,可是没有走分区键。那么结果会很尴尬。若是1000w的B+树的高度是3,如今有10个分区。那么不是要(3+3)*10次的逻辑IO?(3次汇集索引,3次辅助索引,10个分区)。因此在OLTP应用中请当心使用分区表。

在平常开发中,若是想查看sql语句的分区查询结果可使用explain partitions + select sql来获取,partitions标识走了哪几个分区。

mysql> explain partitions select * from TxnList where startTime>'2016-08-25 00:00:00' and startTime<'2016-08-25 23:59:00';  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
| id | select_type | table             | partitions | type | possible_keys | key  | key_len | ref  | rows  | Extra       |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
|  1 | SIMPLE      | ClientActionTrack | p20160825  | ALL  | NULL          | NULL | NULL    | NULL | 33868 | Using where |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
row in set (0.00 sec)

相关文章
相关标签/搜索