细聊MySQL的分区功能
此篇主要介绍下MySQL的分区功能。我们分别从分区的概念、分区对于MySQL应用的优点、分区的类别及设置来和大家一起探讨下MySQL的分区。
什么是分区?
MySQL在未启用分区功能时,数据库的单个表内容是以单个文件的形式存放在文件系统上的。当启用分区功能后,MySQL将按用户指定的规则将单个表内容分割成几个文件存放在文件系统上。分区分为水平分区和垂直分区,水平分区是将表的数据按行分割成不同的数据文件,而垂直分区则是将表的数据按列分割成不同的数据文件。分片要遵循完备性原则、可重构性原则与不相交原则。完备性代表所有数据必须映射到某个片段上。可重构性表示所有分片数据必须可以重新构成全局数据。不相交性表示不同分片上的数据没有重复(除非你是特意做的冗余)。
由于自MySQL 5.7起已不支持垂直分区,所以此篇文章主要介绍数据库的水平分区。
分区的优势
1、由于分区可以将表数据分割成不同的文件,并分配到不同的磁盘,因此分区可以在一个表中存放更多的数据。
2、分区后可以快速的移除不需要的数据或添加新的数据。举个例子,如果按时间范围分区,分区规则为从开始至2010年设置为分区1,2011年至2013年设置为分区2,2014年至现在设置为分区3。如果我想删除2010年之前的数据,那么只用删除分区1即可,而无需扫描整个表。
3、分区可以优化查询,你可以将经常需要被查询的内容设置为一个分区,这样查询数据时就可以直接显示分区的内容。例如,你可以利用SELECT
* FROM t PARTITION(p0,p1) WHERE c <
5来查询p0与p1两个分区下的内容。这样系统扫描的行会更少,加快了查询效率。由于查询条件可能在一段时间后有所变动,此时我们需要重新调整分区规则。所以,数据库是需要经常维护的。
分区类别
我们可以根据范围、列表、哈希与关键字这四种类别进行分区。范围分区是根据用户指定某列的范围值进行分区。列表分区类似于范围分区,但列表分区必须根据用户具体指定的集合进行分区。哈希分区根据用户表达式返回的正整数值进行分区。关键字分区类似与哈希分区,一般根据用户指定的关键列名进行分区。下面,我们就来详细了解下这四种分区的相关用法。
范围分区
我们以例子来说明如何设置范围分区。首先创建一个表
1
2
3
4
5
6
7
8
9
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT NOT NULL , store_id INT NOT NULL ); |
这是一张雇员表,fname为first name,lname为last name,hired为聘用时间,separated为离职时间,job_code为工号,store_id为此雇员属于哪个门店。
我们可以用多种方式对它进行范围分区,可以根据门店ID的范围,聘用时间的范围,工号的范围均可。下面我们根据门店ID的范围对此表进行分区,SQL声明如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT NOT NULL , store_id INT NOT NULL ) PARTITION BY RANGE (store_id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN (21) ); |
在这种分区设置下,门店ID1~5的雇员信息被分配到分区p0中,6~10的雇员信息被分配到分区p1中,以此类推。如果你的store_id确定在1~20之间,此种分区方法是没有问题的。那么,如果你的store_id不确定,当出现store_id的值为大于21的值时,此分区设置就会导致错误,因为我们没有分配store_id大于21时的行到任何一个分区。要解决这个问题,我们需要引进关键字“MAXVALUE”,按如下的SQL声明,即可解决store_id不固定的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT NOT NULL , store_id INT NOT NULL ) PARTITION BY RANGE (store_id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN MAXVALUE ); |
当然,我们也可以按照时间范围来进行分区,具体就看个人的应用场景了。值得注意的是,由于MySQL的bug,在按照时间范围来进行分区时,如果你需要转化成时间戳来分区,则最好使用UNIX_TIMESTAMP函数而不是TIMESTAMP函数。
列表分区
列表分区在我看来是一种比较“笨”的分区方法,因为它得把列中的所有可能值显式写在SQL声明中。还是以employees表为例。我们按store_id,以列表的方式进行分区。假设我们将门店分为东南西北四个区域,北部的门店ID分别为3,5,6,9,17。东部的门店ID分别为1,2,10,11,19,20。西部的门店ID分别为4,12,13,14,18。南部的门店ID分别为7,8,15,16。每一个区域对应一个分区,则列表分区的SQL声明如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT , store_id INT ) PARTITION BY LIST(store_id) ( PARTITION pNorth VALUES IN (3,5,6,9,17), PARTITION pEast VALUES IN (1,2,10,11,19,20), PARTITION pWest VALUES IN (4,12,13,14,18), PARTITION pSouth VALUES IN (7,8,15,16) ); |
与范围分区不同,列表分区中没用类似“MAXVALUE”这种用法,我们必须覆盖所有可能的值。如果插入一个store_id为21的记录,则系统将会报错。
哈希分区
哈希分区的设置很简单,只需保证用户指定的表达式为正整数,并且显式设置分区个数即可。分区个数也需为正整数。如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT , store_id INT ) PARTITION BY HASH( YEAR (hired) ) PARTITIONS 4; |
YEAR(hired)为用户设置的表达式,返回正整数。需要注意的是表达式的结果值与指定的列值最好成线性关系,否则,分区的数据将不能均匀的分布。如果要确认某个记录分布在哪个分区,可以使用N
= MOD(expr, num)的公式进行确认。MOD为取模,N为记录所在的分区,expr为YEAR(hired)的值,num为4
(根据上例的值所得)。那么如果expr的值为2005,则记录所在的分区为第一分区。
线性哈希分区
线性哈希分区与普通哈希分区在确定记录所在分区的算法上有一定区别,其它并无不同之处,线性哈希分区的SQL声明如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
CREATE TABLE employees ( id INT NOT NULL , fname VARCHAR (30), lname VARCHAR (30), hired DATE NOT NULL DEFAULT '1970-01-01' , separated DATE NOT NULL DEFAULT '9999-12-31' , job_code INT , store_id INT ) PARTITION BY LINEAR HASH( YEAR (hired) ) PARTITIONS 4; |
关键字分区
关键字分区需以表中的主键或唯一列来作为分区的关键字指定,否则将不能成功设置。关键字分区的SQL声明如下:
1
2
3
4
5
|
CREATE TABLE tm1 ( s1 CHAR (32) PRIMARY KEY ) PARTITION BY KEY (s1) PARTITIONS 10; |
可以看到,关键字的类型并不一定是需要正整数,字符型的列也可以作为关键字。
除以上介绍的分区外,MySQL还能设置列分区与子分区。那么,什么是列分区,什么是子分区呢?下面我们简单的了解下。
子分区,子分区就是分区下的分区,将每个分区继续细分,变成更小的分区。有这种需求的,可能是单表数据量非常大的场景吧。具体的设置方式如下所示:
1
2
3
4
5
6
7
8
|
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 p1 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN MAXVALUE ); |
此声明将ts表按范围分成p0,p1,p2三个分区,又将p0,p1,p2每个分区用哈希分区分成了p0-1和p0-2(p1,p2以此类推)两个子分区。实际上,此声明是将表分成了6个分区。
还有更加详细的子分区法,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
CREATE TABLE ts (id INT , purchased DATE ) PARTITION BY RANGE( YEAR (purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0 DATA DIRECTORY = '/disk0/data' INDEX DIRECTORY = '/disk0/idx' , SUBPARTITION s1 DATA DIRECTORY = '/disk1/data' INDEX DIRECTORY = '/disk1/idx' ), PARTITION p1 VALUES LESS THAN (2000) ( SUBPARTITION s2 DATA DIRECTORY = '/disk2/data' INDEX DIRECTORY = '/disk2/idx' , SUBPARTITION s3 DATA DIRECTORY = '/disk3/data' INDEX DIRECTORY = '/disk3/idx' ), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s4 DATA DIRECTORY = '/disk4/data' INDEX DIRECTORY = '/disk4/idx' , SUBPARTITION s5 DATA DIRECTORY = '/disk5/data' INDEX DIRECTORY = '/disk5/idx' ) ); |
此声明首先利用范围分区将表分成了p0,p1,p2三个分区,然后利用哈希分区将p0细分为s0,s1两个分区,s0的数据文件路径为/disk0/data,索引文件路径为/disk0/idx,以此类推。最后的分区为s0,s1,s2,s3,s4,s5。
列分区
列分区就是利用多个列值进行分区,范围分区与列表分区都支持列分区。列分区不支持表达式,只支持列名,但列名可以是多个。列分区是通过比较多个列值形成的元组进行分区。下面我们范围列分区来介绍下列分区,SQL声明如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
mysql> CREATE TABLE rcx ( -> a INT , -> b INT , -> c CHAR (3), -> d INT -> ) -> PARTITION 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) -> ); Query OK, 0 rows affected (0.15 sec) |
此声明依据a,d,c三列进行范围分区。通过比较(5,10,’ggg’),(10,20,’mmmm’),(15,30,’sss’)来对表中的数据进行分割。由于对于元组的范围判断本人也不是太清楚,保证不了分区的完备性原则,所以这里就不详细介绍列分区了。对列分区有兴趣的同学可以自行查看手册。
关于MySQL的分区今天就先聊到这,具体使用哪种类型的分区,分多少区还要看各位的具体应用场景和应用逻辑来决定,不能一概而论。
细聊MySQL的分区功能的更多相关文章
- mysql数据库分区功能及实例详解
分区听起来怎么感觉是硬盘呀,对没错除了硬盘可以分区数据库现在也支持分区了,分区可以解决大数据量的处理问题,下面一起来看一个mysql数据库分区功能及实例详解 一,什么是数据库分区 前段时间写过一篇 ...
- 2 万字 + 30 张图 | 细聊 MySQL undo log、redo log、binlog 有什么用?
作者:小林coding 计算机八股文网站:https://xiaolincoding.com/ 大家好,我是小林. 从这篇「执行一条 SQL 查询语句,期间发生了什么?」中,我们知道了一条查询语句经历 ...
- mysql分区功能详细介绍,以及实例
一,什么是数据库分区 前段时间写过一篇关于mysql分表的 的文章,下面来说一下什么是数据库分区,以mysql为例.mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下 ...
- MySQL数据库表分区功能详解
1.什么是表分区? mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表 ...
- mysql分区功能(三个文件储存一张表)(分区作用)(分区方式)
mysql分区功能(三个文件储存一张表)(分区作用)(分区方式) 一.总结 1.mysql数据表的存储方式(三个文件储存一张表): 一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放 ...
- MySQL的分区、分表、集群
1.分区 mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一 ...
- mysql表分区实战
一,什么是数据库分区以mysql为例,mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面 (可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件 ...
- mysql表分区 partition
表分区 partition 当一张表的数据非常多的时候,比如单个.myd文件都达到10G, 这时,必然读取起来效率降低. 可不可以把表的数据分开在几张表上? 1: 从业务角度可以解决.. (分表,水平 ...
- MySQL COLUMNS分区
200 ? "200px" : this.width)!important;} --> 介绍 COLUMN分区是5.5开始引入的分区功能,只有RANGE COLUMN和LIS ...
随机推荐
- OneDrive 开机启动设置失效如何处理?
问题现象: 『设置里勾选了开机启动onedrive,但是重启电脑勾选就没了,重新勾选没用,一重启就没了』 win10的onedrive无法开机启动 - Microsoft Community 处理方式 ...
- jQuery记忆巩固
jQuery是由原生js写的所以说所有jQuery制作出来的效果都可以使用js做出来,jQuery出现的目的是为了优化代码,提高码代码的效率它将很多功能封装. 一.jQuery的认识 1.何为jque ...
- 汉化 的 空指针 bug
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha nulljava.lang.NullPointerException at com.an ...
- 递归与分治策略之棋盘覆盖Java实现
递归与分治策略之棋盘覆盖 一.问题描述 二.过程详解 1.棋盘如下图,其中有一特殊方格:16*16 . 2.第一个分割结果:8*8 3.第二次分割结果:4*4 4.第三次分割结果:2*2 5.第四次分 ...
- Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)
这题需要维护连通性,看到有连接删除,很容易直接就想LCT了.然而这题点数20w操作10w,LCT卡常估计过不去.看到这个东西只有两行,考虑能否用魔改后的线性数据结构去维护.我想到了线段树. 考虑如果两 ...
- HDU.2899.Strange fuction(牛顿迭代)
题目链接 \(Description\) 求函数\(F(x)=6\times x^7+8\times x^6+7\times x^3+5\times x^2-y\times x\)在\(x\in \l ...
- N!(N的阶乘)最末位非0的求解方法
问题是求关于N!的最后一位非0位, 如3!=6,最后一位非0位为6, 5!=120, 最后一位非0位为2.怎么样快速的求出最后一位非0位呢? 最朴素的想法就是先求出N!的结果,再求出结果的最后一位非0 ...
- Windows下修改Git bash的HOME路径
Windows中使用http://git-scm.com/安装Git bash工具,默认的HOME和~路径一般都是C:\Users\用户名,每次得用命令切换到常用的Repository下,此操作重复而 ...
- Mysql的学习随笔day1
关于mysql的基本语句 ps:[]是缺省 创建:CREATE DATABASE db.name CREATE TABLE name(列名,类型,[NULL])NOT NULL是不需要为空,NOT ...
- 所谓jQuery.append()、jQuery.html()存在的XSS漏洞
使用jQuery.append().jQuery.html()方法时,如果其中内容包含<script>脚本而没有经过任何处理的话,会执行它. 简单的示例代码如下: var xssStr = ...