细聊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的分区今天就先聊到这,具体使用哪种类型的分区,分多少区还要看各位的具体应用场景和应用逻辑来决定,不能一概而论。

原文地址:https://www.cnblogs.com/wanghuaijun/p/8185341.html

时间: 2024-10-10 02:26:55

细聊MySQL的分区功能的相关文章

mysql数据库分区功能及实例详解

分区听起来怎么感觉是硬盘呀,对没错除了硬盘可以分区数据库现在也支持分区了,分区可以解决大数据量的处理问题,下面一起来看一个mysql数据库分区功能及实例详解 一,什么是数据库分区 前段时间写过一篇关于mysql分表的的文章,下面来说一下什么是数据库分区,以mysql为例.mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存

细聊MySQL的Innodb存储引擎(完)

细聊MySQL的Innodb存储引擎(一) 细聊MySQL的Innodb存储引擎(二) 细聊MySQL的Innodb存储引擎(完) 上篇主要和大家探讨了Innodb引擎中出现幻读的处理方法与死锁的探测及避免死锁的一些注意事项.此篇,我们来研究下Innodb的索引. Innodb里涉及到的索引主要有四种,分别为聚簇索引(Clustered Index).次级索引(Secondary Index).全文索引(FULLTEXT Index).哈希索引(Hash Index). 聚簇索引与次级索引 每一

细聊MySQL的Innodb存储引擎(二)

细聊MySQL的Innodb存储引擎(一) 上一篇主要和大家探讨了下Innodb的锁机制与隔离机制.本篇来和大家一起研究下在使用Innodb是会出现的问题以及如何解决它们. Innodb是如何解决幻读问题的 什么是幻读?听起来似乎很高端,但实际上它只是反映了事务中的一种数据不一致的情况.下面看我来描述这样一个场景,通过这个场景,大家就能很清楚的知道幻读到底是什么意思. 打开两个客户端,设为A和B A客户端 mysql> start transaction; (步骤一) Query OK, 0 r

细聊MySQL之常用工具及基本操作(二)

接细聊MySQL之常用工具及基本操作(一) 四.客户端管理工具mysqlcheck的使用.mysqlcheck是客户端表维护工具,可以检查.修复.优化或分析表. 如 shell> mysqlcheck databasename tablename [options] databasename为数据库名 tablename为表名 如果你只指定databasename,通常会检查databasename下所有的表.如果你既不指定databasename,也不指定tablename,那么一定要添加参数

细聊MySQL之常用工具及基本操作(三)

细聊MySQL之常用工具及基本操作(一) 细聊MySQL之常用工具及基本操作(二) 七.使用mysqlshow工具查看数据库.表和列的信息.具体语法: shell> mysqlshow [options] [db_name [tbl_name [col_name]]] 注:如果没有数据库给定,列出数据库列表 如果没有表给定,列出所有数据库的表 如果没有列给定,列出表内所有的列 详细参数如下: 参数 描述 适用 弃用 --bind-address=ip_address 同mysql命令 --com

细聊MySQL的安全机制

MySQL作为系统的数据库,在安全性方面有非常高的要求.如果一个系统的数据库被非法进入或窃听,则系统的数据将受到非常严重的威胁,轻则数据.密码被盗,重则导致整个系统瘫痪.所以数据库的安全对于系统来说是非常重要的. 本文将从MySQL的服务器启动与客户端访问.操作及链路三方面来阐述MySQL的安全机制. 一.MySQL的服务器启动与客户端访问.        1.服务器启动,启动服务器在安全方面的影响主要是启动它的用户.默认情况下,MySQL不允许使用root账号启动.我们应该建立一个只能操作My

细聊MySQL的备份与恢复

备份对于数据库来说是相当重要的工作.如果数据库在使用过程中出现了问题,比如系统崩溃.硬件故障或错误的删除了数据.这时,如果我们进行了数据备份,就能比较方便的使数据库恢复工作,并使我们的数据损失到最小.下面,我从备份类型.备份方法及一些常用的例子来和大家详细探讨下数据库的备份与恢复. 一.备份类别 1.物理备份与逻辑备份 物理备份用人话来形容就是复制数据库的数据文件.如果我们需要备份名为test的数据库,则我们可以将数据目录下的test目录复制到备份设备中.如果我们需要备份test库下名为user

细聊MySQL之常用工具及基本操作(一)

一.对于MySQL用户来说,使用MySQL的第一步就是启动它.要启动MySQL,我们需要mysqld或mysqld_safe命令.默认情况下,直接执行mysqld或mysqld_safe即可.如 shell> mysqld & 或 shell> mysqld_safe &.当然不是所有事情都那么顺利,如果启动不了,请指定相关的参数.服务器运行的前提是你已经执行了mysql_install_db脚本.当然,如果就这样启动,将有很多功能启动不了.如没有binlog,当某一天你不小心

细聊MySQL的Innodb存储引擎(一)

从MySQL5.5开始,Innodb就成为MySQL的默认存储引擎了.可想而知,Innodb已经成为MySQL的主要生产方式.那Innodb到底有什么本事能够击败其它几位存储引擎而荣登宝座呢?下面,我就来和大家一起探讨探讨牛逼的Innodb引擎.Innodb涉及到的知识点比较多,所以我会分几篇来叙述,此篇主要介绍Innodb的基本概念和架构. 要了解Innodb,首先需要了解MySQL的ACID模型.何为ACID?ACID指的是事务的原子性(A).一致性(C).隔离性(I).持久性(D). 原子